Как заставить Ruby RestClient gem уважать content_type в сообщении?

Например, в консоли RestClient:

RestClient.post 'http://localhost:5001', {:a => 'b'}, :content_type => 'application/json'

Это не отправляет application/json в качестве типа содержимого. Вместо этого я вижу:

Content-Type: application/x-www-form-urlencoded

Мне удалось проследить изменение в restclient/payload.rb:

  class UrlEncoded < Base
  ...

  def headers
    super.merge({'Content-Type' => 'application/x-www-form-urlencoded'})
  end
end

Замена super.merge на super приводит к тому, что тип контента должен соблюдаться, но, очевидно, это не настоящее решение. Кто-нибудь знает, как правильно это исправить? Спасибо.

Ответ 1

Возможно, вы захотите поставить json как строку как свою полезную нагрузку вместо хэша. Например, do:

RestClient.post 'http://localhost:5001','{"a":"b"}',:content_type => 'application/json'

Если вы посмотрите на payload.rb, он покажет, что он будет использовать базовую клану вместо класса UrlEncoded, если полезная нагрузка является строкой. Попробуйте это и посмотрите, работает ли это для вас.

Ответ 2

Факт

Для запроса :post, когда payload является Hash, заголовок Content-Type всегда будет переопределен на application/x-www-form-urlencoded.

Восстанавливается с помощью rest-client (2.0.0).

Решение

Преобразование хэш-полезной нагрузки в строку json.

require 'json'

payload.to_json

В репозитории rest-client есть :

Ответ 3

Я хотел бы добавить, что моя проблема заключалась в использовании RestClient::Request.execute (в отличие от RestClient.post или RestClient.get).

Проблема заключалась в том, как я устанавливал :content_type и :accept. Из примеров, которые я видел, казалось, что они должны быть такими, как:

res = RestClient::Request.execute(
  :method => :get,
  :url => url,
  :verify_ssl =>  false,
  :content_type => :json,
  :accept => :json,
  :headers => { 
    :Authorization => "Bearer #{token}", 
  },
  :payload => '{"a":"b"}'
)

Но вы действительно должны помещать их в :headers следующим образом:

res = RestClient::Request.execute(
  :method => :get,
  :url => url,
  :verify_ssl =>  false,
  :headers => { 
    :Authorization => "Bearer #{token}", 
    :content_type => :json,
    :accept => :json
  },
  :payload => '{"a":"b"}'
)

Ответ 4

Я пытался отправить имя пользователя и пароль, наряду с токенами csrf и файлом cookie авторизации, через POST в формате данных формы. Преобразование полезной нагрузки в json и явная настройка заголовка типа контента не помогли. В итоге я передал полезную нагрузку в виде строки запроса и удалил ее преобразование в JSON:

RestClient::Request.execute(
  method: :post, 
  url: 'http://app_url/login.do',
  payload: "username=username&password=password&_csrf=token",
  headers: {'X-XSRF-TOKEN' => 'token'},
  cookies: {'XSRF-TOKEN' =>  cookie_object}
)

Другой вариант также будет использовать encode_www_form, но строка запроса лучше подходит для моего конкретного случая использования.

Хотя это не распространенный случай и все зависит от формата параметров, ожидаемого серверной частью, все же целесообразно передать строку запроса в теле POST, если сервер ожидает кодирование URL в качестве тела POST. Надеюсь, это может кому-то помочь.