Ruby脚本不向服务器发送POST请求的主体

时间:2011-07-11 14:36:39

标签: ruby post request webserver

我正在Ruby中编写一个模拟服务器来测试我们的内部API。我想在服务器响应中包含一个POST请求体。我使用Net::HTTP::ServerNet::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:  

我做错了什么?

相关:Parse body of POST reqest in self-made server in Ruby

3 个答案:

答案 0 :(得分:2)

不支持发布请求。它们不包含在规范中。如果请求主体内容长度不是4096的倍数,则调用stream.body将阻塞。

https://github.com/postmodern/net-http-server/blob/master/lib/net/http/server/stream.rb调用

IO.read(4096, '')

如果您事先不知道尺寸,可以通过非阻塞方式读取插座来解决。例如,下面的处理程序将尝试读取Request主体,然后只需在Response主体中返回它。如果标题中提供了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 :(得分:1)

我认为net-http-server存在问题。

尝试使用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

答案 2 :(得分:1)

此刻我正在做类似的事情。对于“快速和肮脏”测试,我建议curl。例如:

获取:

curl http://localhost:3000/locations"

发表:

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"

删除:

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