2010-04-12 6 views
5

Tôi đang xây dựng một số loại proxy.
Khi tôi gọi một số url trong ứng dụng giá, tôi chuyển tiếp yêu cầu đó đến một url khác.Đăng yêu cầu với body_stream và thông số

Yêu cầu tôi chuyển tiếp là POST có tệp và một số tham số.
Tôi muốn thêm các thông số khác.
Nhưng tệp có thể khá lớn. Vì vậy, tôi gửi nó với Net::HTTP#body_stream thay vì Net::HTTP#body.

Tôi nhận được yêu cầu của mình là đối tượng Rack::Request và tôi tạo đối tượng Net :: HTTP của mình với điều đó.

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) 

Tôi đã thử một số cách để thêm thông số của proxy. Nhưng có vẻ như không có gì trong Net :: HTTP cho phép thêm các tham số vào một yêu cầu body_stream, chỉ cho một yêu cầu cơ thể.

Có cách nào đơn giản hơn để ủy quyền yêu cầu giá như vậy không? Hoặc một cách sạch sẽ để thêm các tham số của tôi vào yêu cầu của tôi?

+0

tại sao 'req.set_form_data (: some => 'data')' không hoạt động? – mikezter

+0

Vì nó định nghĩa '# body' và đặt lại' # body_stream' nên tôi mất tất cả dữ liệu được xác định trước đó. –

Trả lời

3

Vâng .. như tôi thấy, đây là hành vi bình thường. Tôi sẽ giải thích tại sao. Nếu bạn chỉ có quyền truy cập vào một Rack :: Yêu cầu, (tôi đoán rằng) middleware của bạn không phân tích cú pháp phản hồi (bạn không bao gồm một cái gì đó như ActionController :: ParamsParser), do đó bạn không có quyền truy cập vào một băm các tham số, nhưng với một StringIo. StringIO này tương ứng với một dòng 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-- 

gì bạn đang cố gắng để làm với Net :: HTTP lớp là: (1). phân tích cú pháp yêu cầu thành một băm thông số; (2). hợp nhất các tham số băm với các tham số của riêng bạn; (3). tạo lại yêu cầu. Vấn đề là Net :: HTTP thư viện không thể làm (1), vì nó là một thư viện khách hàng, không phải là một máy chủ.

Vì vậy, bạn không thể thoát khỏi phân tích cú pháp một số yêu cầu của bạn trước khi thêm thông số mới.

giải pháp có thể:

  1. Chèn ActionController :: ParamsParser trước middleware của bạn. Sau đó, bạn có thể sử dụng tuyệt vời rest-client lib để làm một cái gì đó như:

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

  2. Bạn có thể cố gắng để tạo một trình bao bọc trên đối tượng StringIO và thêm vào cuối luồng, các tham số của riêng bạn. Tuy nhiên, đây không phải là tầm thường cũng không khuyến khích.

+0

Vâng, tôi bỏ cái thứ hai. Tôi sẽ thử đầu tiên. Cảm ơn :) –

+0

Bạn được chào đón :) Tuy nhiên, bằng cách phân tích cú pháp yêu cầu theo cách này, bạn phải đợi toàn bộ nội dung được tải lên máy chủ proxy. Do đó, total_time> time_to_upload_to_proxy + time_to_upload_to_real_server. –

0

Có thể là một năm quá trễ, nhưng tôi đã gặp sự cố tương tự khi xác minh IPN của Paypal. Tôi muốn gửi lại yêu cầu IPN đến Paypal để xác minh nhưng cần thêm: cmd => '_notify-validate'.

Thay vì sửa đổi dòng cơ thể, hoặc cơ thể, tôi gắn nó như là một phần của đường dẫn URL, như vậy:

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

Có vẻ như một chút của một hack, nhưng tôi nghĩ rằng nó có giá trị nó nếu bạn sẽ không sử dụng nó cho bất cứ điều gì khác.