Сценарий Ruby не отправляет тело запроса POST на сервер - PullRequest
1 голос
/ 11 июля 2011

Я пишу фиктивный сервер на Ruby для тестирования нашего внутреннего API. Я хотел бы включить тело запроса POST в ответ сервера. Я использую Net :: HTTP :: Server и Net :: HTTP класс. Прямо сейчас макет сервера выглядит так:

require 'net/http/server'
require 'pp'
require 'json'

Net::HTTP::Server.run(:port => 8080) do |request,stream|
  pp request
  [200, {'Content-Type' => 'text/html'}, [request[:body]]]
end

Сценарий, который отправляет POST-запрос с телом, выглядит так:

require 'net/http'
require 'uri'

url = URI.parse(http://localhost:8080/)
x = {"country" => "Ukraine", "city" => 'Kiev'}

http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Post.new(url.path)
request.set_form_data(x)
response = http.request(request)

puts "Request body: #{request.body}"
puts "Response Body: #{response.body}"

Однако журнал сервера указывает, что запрос POST не содержал тела:

#Output from server    
{:method=>"POST"@0,
 :uri=>{:path=>"/"},
 :version=>"1.1"@12,
 :headers=>
  {"Accept"@17=>"*/*"@25,
   "User-Agent"@30=>"Ruby"@42,
   "Content-Type"@48=>"application/x-www-form-urlencoded"@62,
   "Connection"@97=>"close"@109,
   "Host"@116=>"localhost:8080"@122,
   "Content-Length"@138=>"25"@154}}

#Output from script file:
Request body: country=Ukraine&city=Kiev
Response body:  

Что я сделал не так?

Related: Анализировать тело запроса POST на самодельном сервере в Ruby

Ответы [ 3 ]

2 голосов
/ 08 февраля 2013

Почтовые запросы не поддерживаются. Они не включены в спецификацию. Вызов stream.body будет заблокирован, если длина содержимого тела запроса не кратна 4096.

Потому что https://github.com/postmodern/net-http-server/blob/master/lib/net/http/server/stream.rb звонит

IO.read(4096, '')

Вы можете обойтись, читая сокет неблокирующим способом, если вы не знаете размер заранее. Например, следующий обработчик попытается прочитать тело запроса, а затем просто вернуть его в теле ответа. Если Content-Length указан в заголовке, он будет блокировать ожидание потока, чтобы отправить достаточно данных до указанного количества байтов.

class PostHandler
 BUF_SIZE = 4096

 def call(request, stream)
    case request[:method].to_s
    when "POST"
        body = nil
        if request[:headers]["Content-Type"] == "application/x-www-form-urlencoded"
            body = readBlock(stream.socket, request[:headers]["Content-Length"].to_i)
        else
            body = readNonblock(stream.socket)
        end
        unless body.nil?
            return [200, {}, [body] ]
        end
     end 

     [404, {}, [""]]
  end 

  private

  # blocking way to read the stream
  def readBlock(socket, length)
    socket.read(length)
  end

  # non-blocking alternative
  # stop reading as soon as it would block
  def readNonblock(socket)
    buffer = ""
    loop {
       begin
           buffer << socket.read_nonblock(BUF_SIZE)
       rescue Errno::EAGAIN
           # Resource temporarily unavailable - read would block
           break
       end
    }
    buffer
  end

end 
1 голос
/ 11 июля 2011

Я сейчас работаю над подобной вещью. Для «быстрого и грязного» тестирования я бы предложил curl . Например:

GET:

curl http://localhost:3000/locations"

POST:

curl http://localhost:3000/locations -d "location[country]=Ukraine&location[city]=Kiev"

PUT:

curl http://localhost:3000/locations/1 -X PUT -d "location[country]=Ukraine"

DELETE:

curl http://localhost:3000/locations/1 -X DELETE"

Сказав, что для более надежного тестирования, предполагая, что вы используете Rails / Rack, я использую Cucumber для интеграционных тестов для API. где вы можете просто использовать помощники rais / rack, например, в случае использования, для POST:

url = "http://localhost:3000/locations/"
hash = { "location" => { "country => "Ukraine", "city" => "Kiev" }
post url, hash
1 голос
/ 11 июля 2011

Я предполагаю, что это проблема с net-http-сервером.

Попробуйте использовать WEBrick в качестве сервера:

require 'webrick'
include WEBrick   

def start_webrick(config = {})
  config.update(:Port => 8080)     
  server = HTTPServer.new(config)
  yield server if block_given?
  ['INT', 'TERM'].each {|signal| 
    trap(signal) {server.shutdown}
  }
  server.start
end

start_webrick {|server|
  server.mount_proc('/') {|req, resp| 
    resp.body = req.body
  }
}

Это работает для меня, вывод:

country=Ukraine&city=Kiev
...