2010-04-12 102 views
5

我正在建立某種代理。
當我在機架應用程序中調用某個url時,我將該請求轉發給其他url。發佈請求body_stream和參數

我轉發的請求是一個包含文件和一些參數的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請求中,而只能添加到body_stream請求中。

有沒有更簡單的方法來代理這樣的機架請求?或者一個乾淨的方式來添加我的參數到我的請求?

+0

爲什麼'req.set_form_data(:some =>'data')'不起作用? – mikezter 2010-04-16 11:07:24

+0

因爲它定義了'#body'並且重置了'#body_stream',所以我失去了以前定義的所有數據。 – 2010-04-16 13:35:17

回答

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-- 

你正在嘗試與網:: HTTP類做的是:(1)。將請求解析爲參數的散列值; (2)。將參數散列與您自己的參數合併; (3)。重新創建請求。問題是Net :: HTTP庫不能做(1),因爲它是一個客戶端庫,而不是服務器端。

因此,在添加新參數之前,您無法解析一些您的請求。

可能的解決方案:

  1. 插入的ActionController ::你的中間件之前ParamsParser。在這之後,你可以使用優秀rest-client LIB做這樣的事情:

    RestClient.post( '' + request.path_info):PARAMS => params.merge(your_params)

  2. 您可以嘗試在StringIO對象上創建一個包裝器,並在流的末尾添加您自己的參數。但是,這不是微不足道的,也不可取的。

+0

是的,我放棄了第二個。我會嘗試第一個。謝謝:) – 2010-04-18 19:54:06

+0

不客氣:)但是,通過這種方式解析請求,您必須等待整個內容上傳到代理服務器。因此,total_time> time_to_upload_to_proxy + time_to_upload_to_real_server。 – 2010-04-19 15:50:29

0

可能是一年太晚了,但我有同樣的問題驗證貝寶IPNs。我想將IPN請求轉發回PayPal進行驗證,但需要添加:cmd =>'_notify-validate'。

不是修改體流,或身體的,我追加它作爲URL路徑的一部分,就像這樣:

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

這似乎有點一個黑客攻擊,但我認爲這是值得的,如果你不會用於其他任何事情。