2010-04-12 10 views
5

Buduję coś w rodzaju proxy.
Po wywołaniu niektórych adresów URL w aplikacji typu rack, przekazuję tę prośbę do innego adresu URL.Wysyłanie żądania z body_stream i parametrami

Żądanie, które przekazuję, to POST z plikiem i niektórymi parametrami.
Chcę dodać więcej parametrów.
Ale plik może być dość duży. Wysyłam go z Net::HTTP#body_stream zamiast Net::HTTP#body.

Otrzymuję moją prośbę jako obiekt Rack::Request i tworzę z tego obiektu 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) 

Próbowałem na kilka sposobów, aby dodać parametry proxy. Ale wydaje się, że nic w Net :: HTTP pozwala dodawać parametry do żądania body_stream, tylko do jednego body.

Czy istnieje prostszy sposób na wykonanie proxy takiej prośby? Lub czysty sposób, aby dodać moje parametry do mojej prośby?

+0

dlaczego 'req.set_form_data (: some => 'data')' nie działa? – mikezter

+0

Ponieważ definiuje '# body' i resetuje' # body_stream', więc tracę wszystkie wcześniej zdefiniowane dane. –

Odpowiedz

3

Cóż .. jak widzę, to normalne zachowanie. Wyjaśnię dlaczego. Jeśli masz dostęp tylko do Rack :: Request, (domyślam się, że) twoje oprogramowanie pośrednie nie analizuje odpowiedzi (nie dodajesz czegoś takiego jak ActionController :: ParamsParser), więc nie masz dostępu do skrótu parametry, ale do StringIo. Ten StringIO odpowiada strumienia 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-- 

Co próbujesz zrobić z Net :: HTTP klasy jest: (1). przetworzyć żądanie na mieszanie parametrów; (2). połączyć parametry hash z własnymi parametrami; (3). odtwórz żądanie. Problem polega na tym, że biblioteka Net :: HTTP nie może wykonać (1), ponieważ jest to biblioteka klienta, a nie serwer.

Dlatego nie można uciec od analizowania niektórych zapytań przed dodaniem nowych parametrów.

Możliwe rozwiązania:

  1. Insert ActionController :: ParamsParser przed middleware. Po tym, można skorzystać z doskonałą rest-client lib zrobić coś takiego:

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

  2. Można próbować aby utworzyć opakowanie na obiekcie StringIO i dodać na końcu strumienia własne parametry. Jednak nie jest to trywialne ani wskazane.

+0

Tak, odłożyłem drugi. Spróbuję pierwszy. Dzięki :) –

+0

Nie ma za co. :) Jednakże, parsując żądanie w ten sposób, należy poczekać na przesłanie całej zawartości na serwer proxy. Dlatego total_time> time_to_upload_to_proxy + time_to_upload_to_real_server. –

0

Może być o jeden rok za późno, ale miałem ten sam problem z weryfikacją IPN Paypal. Chciałem przesłać żądanie IPN do Paypal w celu weryfikacji, ale musiałem dodać: cmd => '_notify-validate'.

Zamiast modyfikowania strumienia ciała lub ciało, ja dołączana jako część ścieżki URL, tak jak poniżej:

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

Wydaje się trochę hack, ale myślę, że warto, jeśli nie użyjemy go do niczego innego.

Powiązane problemy