2010-04-12 16 views
5

Sto costruendo una sorta di proxy.
Quando chiamo un URL in un'applicazione rack, inoltro la richiesta a un altro URL.Invia richiesta con body_stream e parametri

La richiesta I forward è un POST con un file e alcuni parametri.
Desidero aggiungere altri parametri.
Ma il file può essere abbastanza grande. Quindi lo invio con Net::HTTP#body_stream anziché Net::HTTP#body.

Ricevo la mia richiesta come oggetto Rack::Request e creo il mio oggetto Net :: HTTP con quello.

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) 

Ho provato diversi modi per aggiungere i parametri del proxy. Ma sembra che nulla in Net :: HTTP consenta di aggiungere parametri a una richiesta body_stream, solo a un body uno.

Esiste un modo più semplice per eseguire il proxy di una richiesta di rack in questo modo? O un modo pulito per aggiungere i miei parametri alla mia richiesta?

+0

perché 'req.set_form_data (: some => 'data')' non funziona? – mikezter

+0

Perché definisce '# body' e ripristina' # body_stream', quindi perdo tutti i dati precedentemente definiti. –

risposta

3

Bene .. come vedo, questo è un comportamento normale. Spiegherò perché. Se hai accesso solo a Rack :: Request, (credo che) il tuo middleware non analizzi la risposta (non includi qualcosa come ActionController :: ParamsParser), quindi non hai accesso a un hash di parametri, ma su StringIo. Questo StringIO corrisponde ad un flusso 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-- 

cosa si sta cercando di fare con il Net :: HTTP classe è quello di: (1). analizzare la richiesta in un hash di parametri; (2). unire l'hash dei parametri con i propri parametri; (3). ricreare la richiesta. Il problema è che la libreria Net :: HTTP non può fare (1), poiché è una libreria client, non una server.

Pertanto, non è possibile evitare di analizzare come la richiesta prima di aggiungere i nuovi parametri.

Possibili soluzioni:

  1. Inserire ActionController :: ParamsParser prima del tuo middleware. Dopo di che, è possibile utilizzare l'eccellente rest-client lib fare qualcosa di simile:

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

  2. È possibile tentare per creare un wrapper sull'oggetto StringIO e aggiungere, alla fine del flusso, i propri parametri. Tuttavia, questo non è banale né consigliabile.

+0

Sì, ho messo via il secondo. Proverò il primo. Grazie :) –

+0

Prego :) Tuttavia, analizzando la richiesta in questo modo, è necessario attendere che l'intero contenuto venga caricato sul server proxy. Pertanto, il totale_time> time_to_upload_to_proxy + time_to_upload_to_real_server. –

0

Potrebbe essere un anno troppo tardi, ma ho avuto lo stesso problema verificando gli IPN di Paypal. Volevo inoltrare la richiesta IPN a Paypal per la verifica, ma ho dovuto aggiungere: cmd => '_notifica-convalida'.

Invece di modificare il flusso di corpo, o corpo, io aggiunti come parte del sentiero URL, in questo modo:

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

Sembra un po 'di un hack, ma penso che ne vale la pena se si non lo useranno per nient'altro

Problemi correlati