使用body_stream和参数发布请求

时间:2010-04-12 12:26:40

标签: ruby http proxy rack

我正在建立某种代理 当我在机架应用程序中调用某个URL时,我会将该请求转发给其他URL。

我转发的请求是带有文件和一些参数的POST 我想添加更多参数 但文件可能很大。所以我发送的是Net::HTTP#body_stream而不是Net::HTTP#body

我将我的请求作为Rack::Request对象获取,然后用它创建我的Net :: HTTP对象。

req = Net::HTTP::Post.new(request.path_info)
req.body_stream = request.body
req.content_type = request.content_type
req.content_length = request.content_length

http = Net::HTTP.new(@host, @port)
res = http.request(req)

我尝试了几种添加代理参数的方法。但似乎Net :: HTTP中的任何内容都不允许向body_stream请求添加参数,只能添加到正文中。

是否有更简单的方法来代理这样的机架请求?或者将我的参数添加到我的请求的干净方法?

2 个答案:

答案 0 :(得分:3)

嗯..正如我所看到的,这是一种正常行为。我会解释原因。如果你只能访问Rack :: Request,(我猜)你的中间件不会解析响应(你不包含像 ActionController :: ParamsParser 这样的东西),所以你没有访问参数哈希,但访问StringIo。此StringIO对应于流like

Content-Type: multipart/form-data; boundary=AaB03x
--AaB03x 
Content-Disposition: form-data; name="param1" 
value1
--AaB03x 
Content-Disposition: form-data; name="files"; filename="file1.txt" 
Content-Type: text/plain 
... contents of file1.txt ...
--AaB03x--

您尝试使用Net :: HTTP类的目的是:(1)。将请求解析为参数哈希; (2)。将参数hash与您自己的参数合并; (3)。重新创建请求。问题是Net :: HTTP库不能做(1),因为它是一个客户端库,而不是服务器库。

因此,在添加新参数之前,您无法解析一些您的请求。

可能的解决方案:

  1. 在中间件之前插入ActionController :: ParamsParser。之后,您可以使用优秀的rest-client lib来执行以下操作:

    RestClient.post('http://your_server'+ request.path_info),:params => params.merge(your_params)

  2. 您可以尝试在StringIO对象上创建一个包装器,并在流的末尾添加您自己的参数。但是,这不是微不足道也不可取。

答案 1 :(得分:0)

可能一年太晚了,但我有同样的问题来验证Paypal IPN。我想将IPN请求转发回Paypal进行验证,但需要添加:cmd => '_notify-验证'。

我没有修改正文流或正文,而是将其作为网址路径的一部分添加,如下所示:

reply_request = Net::HTTP::Post.new(url.path + '?cmd=_notify-validate')

这似乎有点像黑客,但我认为如果你不打算用它来做任何其他事情,这是值得的。