2010-04-12 11 views
5

Estoy creando algún tipo de proxy.
Cuando llamo a alguna url en una aplicación de rack, reenvío esa solicitud a otra url.Solicitud de publicación con body_stream y los parámetros

La solicitud que reenvío es una POST con un archivo y algunos parámetros.
Quiero agregar más parámetros.
Pero el archivo puede ser bastante grande. Entonces lo envío con Net::HTTP#body_stream en vez de Net::HTTP#body.

Recibo mi pedido como un objeto Rack::Request y creo mi objeto Net :: HTTP con eso.

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) 

He intentado de varias formas agregar los parámetros del proxy. Pero parece que nada en Net :: HTTP permite agregar parámetros a una solicitud body_stream, solo a uno cuerpo.

¿Hay una forma más simple de proxy de una solicitud de rack así? ¿O una forma limpia de agregar mis parámetros a mi solicitud?

+0

¿por qué 'req.set_form_data (: some => 'data')' no funciona? – mikezter

+0

Porque define '# body' y restablece' # body_stream', así que pierdo todos los datos definidos previamente. –

Respuesta

3

Bueno ... como yo lo veo, este es un comportamiento normal. Explicaré por qué. Si solo tiene acceso a un Rack :: Request, (supongo que) su middleware no analiza la respuesta (no incluye algo como ActionController :: ParamsParser), por lo que no tiene acceso a un hash de parámetros, pero a un StringIo. Este StringIO corresponde a una corriente 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-- 

Lo que estamos tratando de hacer con el Net :: HTTP clase es: (1). analizar la solicitud en un hash de parámetros; (2) fusiona los parámetros hash con tus propios parámetros; (3) recrear la solicitud. El problema es que la biblioteca Net :: HTTP no puede hacer (1), ya que es una biblioteca de cliente, no una de servidor.

Por lo tanto, no puede dejar de analizar cómo su solicitud antes de agregar los nuevos parámetros.

soluciones posibles:

  1. Insertar ActionController :: ParamsParser antes de middleware. Después de eso, es posible utilizar la excelente rest-client lib a hacer algo como:

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

  2. Puede intentar para crear un contenedor en el objeto StringIO y agregar, al final de la transmisión, sus propios parámetros. Sin embargo, esto no es trivial ni aconsejable.

+0

Sí, guardé el segundo. Voy a probar el primero. Gracias :) –

+0

De nada :) Sin embargo, al analizar la solicitud de esta manera, debe esperar a que todo el contenido se cargue en el servidor proxy. Por lo tanto, el total_time> time_to_upload_to_proxy + time_to_upload_to_real_server. –

0

Podría ser un año demasiado tarde, pero tuve el mismo problema al verificar las IPN de Paypal. Quería reenviar la solicitud de IPN a Paypal para la verificación, pero necesitaba agregar: cmd => '_notify-validate'.

En lugar de modificar la corriente del cuerpo, o cuerpo, adjuntas como parte de la ruta URL, así:

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

parece un poco de un truco, pero creo que vale la pena si no lo van a usar para nada más.

Cuestiones relacionadas