2012-04-18 10 views
17

Tengo un método de controlador en Ruby on Rails 3 que acepta la aplicación/JSON como tipo de contenido. Todo esto funciona como se esperaba, pero en realidad no quiero que los rieles automáticamente analicen el JSON en el cuerpo de la solicitud POST. Este método actúa como una puerta de enlace y simplemente envía la información a una cola y puede ser bastante grande. No quiero perder el tiempo procesando los datos en @_params ya que no es necesario.Evite que Ruby on Rails 3 analice la publicación JSON

Creo que podría evitar esto estableciendo el tipo de contenido en el encabezado de la solicitud a otra cosa, pero me gustaría ser semánticamente correcto para las solicitudes HTTP.

¿Cómo puedo desactivar esta funcionalidad?

EDITAR: Más específicamente, ¿cómo puedo editar esta funcionalidad solo para esta ruta?

+0

Usted sabe, si usted pone como JSON y decirle a los carriles para esperar que publicado como JSON, creo que Rails siempre analizará. Para hacer lo que describes, creo que casi quieres montar un punto final de rack en esa ruta y manejar el POST con una utilidad como 'rack_raw_upload' ... Buena pregunta, lo siento, realmente no sé la respuesta. – Andrew

+0

Pensamiento interesante ... Puedo darle una oportunidad y ver cómo va. – Macdiesel

Respuesta

13

El análisis de parámetros se hornea bastante profundamente dentro de lib/action_dispatch/middleware/params_parser.rb de actionpack.

Yo diría que lo mejor que vas a conseguir es interceptar la solicitud con Rack, algo como esto.

En lib/raw_json.rb

module Rack 
    class RawJSON 
    def initialize(app) 
     @app = app 
    end 

    def call(env) 
     request = Request.new(env) 
     if request.content_type =~ /application\/json/i 
     # test request.path here to limit your processing to particular actions 
     raw_json = env['rack.input'].read 
     env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded' 
     env['rack.input'] = StringIO.new("raw_json=#{raw_json}") 
     end 
     return @app.call(env) 
    end 
    end 
end 

En config.ru, insertar este antes de la llamada a run <your app name>::Application

require 'raw_json' 
use Rack::RawJSON 
+0

parece que todo lo que necesita agregar a esta solución es detectar una determinada ruta, p. 'if request.path == '/ foo' y request.content_type = ~/application \/json/i' –

+0

Sí, es por eso que puse un comentario en el código para probar request.path. –

+0

No he intentado esto todavía, pero parece una solución bastante razonable, lo intentaré. – Macdiesel

1

La sobrecarga para analizar el JSON a partir de una única solicitud es relativamente bajo. ¿Tiene una razón específica para creer que procesar el JSON está contribuyendo a cualquier tipo de lentitud en el procesamiento general?

De lo contrario, le recomendaría que deje esto tal como está hasta que se pueda identificar como un problema.

Configuración de rieles para no analizar que JSON (ya sea a través de algún tipo de configuración de rack o en algún otro método) creará en a fin de una ruta de la aplicación que no se maneja en un estándar rieles Camino.

Finalmente, es posible que tenga que realizar algún tipo de procesamiento de estos datos. O tal vez deberás poner algún tipo de seguridad frente a él. O tal vez quieras iniciar sesión y relacionarla con el usuario que la envió. Y cuando llegue ese día, usted (u otra persona en su equipo) deberá ingresar y realizar cambios a esta implementación no estándar.

Hacer cosas de una forma no estándar en una implementación de Rails puede aumentar la complejidad y el tiempo para mantener el software. También es una fuente común de defectos ya que las personas están menos familiarizadas con el procesamiento no estándar.

Así que a menos que sea un problema real, yo recomendaría simplemente dejar que los rieles procesen el JSON y luego simplemente pasarlo a través del Rails Way normal.

+1

Esto no responde la pregunta. Estoy buscando no analizar la respuesta JSON entrante principalmente por el bien de la optimización. El cuerpo JSON podría ser una matriz con decenas de miles de elementos y tener que analizar e iterar sobre esto le quitará tiempo y memoria a la aplicación cuando podría/debería estar haciendo otras cosas. Esta acción es simplemente un pase para los datos. – Macdiesel

+0

NO es relativamente bajo en absoluto, Rails analiza toda la entrada, filtra y registra TODOS los parámetros y el costo es ENORME cuando se trata de muchas solicitudes de 100k de tamaño. – lzap

1

Se puede hornear en, pero mirando el código:

module ActionDispatch 
    class ParamsParser 
    DEFAULT_PARSERS = { 
     Mime::XML => :xml_simple, 
     Mime::JSON => :json 
    } 

    def initialize(app, parsers = {}) 
     @app, @parsers = app, DEFAULT_PARSERS.merge(parsers) 
    end 

    [ ... ] 

     strategy = @parsers[mime_type] 

Por lo tanto, si se puede organizar para enviar un hash a esta inicialización, se puede añadir o reemplazar el valor predeterminado. No estoy seguro de que permita la eliminación, pero podría funcionar un método de analizador vacío.

analizadores respuesta aquí: How do I initialize ActionDispatch::ParamsParser in Rails 3.1?

Código es de actionpack-3.2.8/lib/action_dispatch/middleware/params_parser.rb