Как отправить двоичные данные через HTTP-запрос с использованием Ruby gem?

#ruby #http

#ruby #http

Вопрос:

Я пытаюсь найти способ воспроизвести HTTP-запрос, который отправляет двоичные данные в полезной нагрузке, а также задает Content-Type: binary заголовок, как следующая команда с cURL:

 echo -e 'x14x00x00x00x70x69x6ex67x00x00' | curl -X POST 
-H 'Content-Type: binary' 
-H 'Accept: */*' 
-H 'Accept-Encoding: gzip,deflate,sdch' 
-H 'Accept-Language: en-US,en;q=0.8,pt;q=0.6' 
-H 'Cookie: JSESSIONID=m1q1hkaptxcqjuvruo5qugpf' 
--data-binary @- 
--url 'http://202.12.53.123' 
--trace-ascii /dev/stdout
  

Я уже пробовал использовать REST Client (https://github.com/rest-client/rest-client ) и HttpClient (https://github.com/nahi/httpclient), но безуспешно. Используя приведенный ниже код, сервер ответил HTTP 500. Кто-нибудь делал это раньше или это невозможно для целей, для которых были разработаны драгоценные камни?

Ruby code:

 require 'rest-client'
request = RestClient::Request.new(
  :method => :post, 
  :url => 'http://202.12.53.123', 
  :payload => %w[14 00 00 00 70 69 6e 67 00 00], 
  :headers => {
    :content_type => :binary,
    :accept => '*/*',
    :accept_encoding => 'gzip,deflate,sdch',
    :accept_language => 'en-US,en;q=0.8,pt;q=0.6',
    :cookies => {'JSESSIONID' => 'm1q1hkaptxcqjuvruo5qugpf'}
  }
)
request.execute
  

ОБНОВЛЕНИЕ (с одним из возможных решений)

В итоге я выполнил запрос с помощью HTTParty (следуя указаниям, данным @DemonKingPiccolo), и это сработало. Вот код:

 require 'httparty'
hex_data = "14 00 00 00 70 69 6e 67 00 00"
response = HTTParty.post(
  'http://202.12.53.123', 
  :headers => {
    'Content-Type' => 'binary',
    'Accept-Encoding' => 'gzip,deflate,sdch',
    'Accept-Language' => 'en-US,en;q=0.8,pt;q=0.6'
  },
  :cookies => {'JSESSIONID' => 'm1q1hkaptxcqjuvruo5qugpf'},
  :body => [hex_data.gsub(/s /,'')].pack('H*').force_encoding('ascii-8bit')
)
puts response.body, response.code, response.message, response.headers.inspect
  

Тело также может быть написано, как предложено @gumbo:

 %w[14 00 00 00 70 69 6e 67 00 00].map { |h| h.to_i(16) }.map(amp;:chr).join
  

Комментарии:

1. httparty мог бы это сделать.

2. Вы сказали, что пытались «безуспешно», но что это значит?

3. %w[14 00 00 00 70 69 6e 67 00 00] делает не то, что вы можете подумать. Это создает массив, эквивалентный ["14", "00", "00", "00", "70", "69", "6e", "67", "00", "00"] . Может быть, вы скорее ищете %w[14 00 00 00 70 69 6e 67 00 00].map { |h| h.to_i(16) }.map(amp;:chr).join

4. Кстати, binary это недопустимое значение для Content-Type заголовка. Content-Type ожидает значение в формате MIME-типа, т. е. type/subtype . При отправке двоичных данных, которые вы обычно хотите использовать application/octet-stream .

5. Вместо того, чтобы выполнять все эти операции с hex_data ( gsub , pack , map и т.д.), Почему бы просто не использовать строку с экранируемыми символами, как в моем примере? "x14x00x00x00x70x69x6ex67x00x00" приведет к тому же самому.

Ответ №1:

Я только что попробовал это, и это сработало как шарм:

 require "net/http"

uri = URI("http://example.com/")

http = Net::HTTP.new(uri.host, uri.port)

req = Net::HTTP::Post.new(uri.path)
req.body = "x14x00x00x00x70x69x6ex67x00x00"
req.content_type = "application/octet-stream"

http.request(req)
# => #<Net::HTTPOK 200 OK readbody=true>
  

Я проверил, что данные размещены правильно, используя RequestBin.

Net:: HTTP действительно груб по краям и не очень интересен в использовании (например, вам приходится форматировать заголовки файлов cookie вручную). Его главное преимущество в том, что он находится в стандартной библиотеке. Такой gem, как RestClient или HTTParty, может быть лучшим выбором, и я почти уверен, что любой из них будет обрабатывать двоичные данные по крайней мере так же легко.

Комментарии:

1. Спасибо @jordan, что представил мне Net :: HTTP. Я отредактировал описание вопроса с другими возможными решениями, которые я нашел.

2. В следующей строке: req = NET::HTTP::Post.new(uri.path) исправлена опечатка, это: req = Net :: HTTP::Post.new(uri.path)