6

我正在构建某种代理。
当我在机架应用程序中调用某个 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 请求中,只能添加到正文中。

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

4

2 回答 2

4

好吧..在我看来,这是正常行为。我会解释为什么。如果您只能访问 Rack::Request,(我猜)您的中间件不会解析响应(您不包括ActionController::ParamsParser 之类的东西),因此您无法访问参数哈希,但是到一个StringIo。此 StringIO 对应于如下流:

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)。将参数哈希与您自己的参数合并;(3)。重新创建请求。问题是 Net::HTTP 库不能做 (1),因为它是客户端库,而不是服务器库。

因此,在添加新参数之前,您无法逃避解析您的请求的方式。

可能的解决方案:

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

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

  2. 您可以尝试对 StringIO 对象进行包装,并在流的末尾添加您自己的参数。然而,这不是微不足道的,也不是可取的。

于 2010-04-18T19:39:57.300 回答
0

可能为时已晚一年,但我在验证 Paypal IPN 时遇到了同样的问题。我想将 IPN 请求转发回 Paypal 进行验证,但需要添加:cmd => '_notify-validate'。

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

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

这似乎有点骇人听闻,但我认为如果你不打算将它用于其他任何事情,它是值得的。

于 2011-07-13T04:35:26.130 回答