2012-04-18 19 views
17

Ho un metodo controller in Ruby on Rails 3 che accetta l'applicazione/JSON come tipo di contenuto. Tutto funziona come previsto, ma in realtà non voglio che i binari analizzino automaticamente il JSON nel corpo della richiesta POST. Questo metodo funge da gateway e trasporta le informazioni in una coda e potrebbe essere abbastanza grande. Non voglio perdere tempo a elaborare i dati negli @_params poiché non è necessario.Previene ruby ​​on rails 3 dall'analisi JSON post

Credo di poter aggirare questo impostando il tipo di contenuto nell'intestazione della richiesta a qualcos'altro, ma mi piacerebbe essere semanticamente corretto per le richieste HTTP.

Come disabilitare questa funzionalità?

MODIFICA: in modo più specifico come posso modificare questa funzionalità solo per questo percorso?

+0

Sai, se si posta come JSON e dire rotaie per invitare per essere pubblicato come JSON, penso che Rails sarà sempre analizzato. Per fare ciò che stai descrivendo penso che tu voglia quasi montare un endpoint rack su quella rotta e gestire il POST con un'utilità come 'rack_raw_upload' ... Buona domanda, scusami, non so davvero la risposta. – Andrew

+0

Pensiero interessante ... Potrei dare un colpo e vedere come va. – Macdiesel

risposta

13

L'analisi dei parametri viene elaborata in modo piuttosto approfondito all'interno di Actionpack lib/action_dispatch/middleware/params_parser.rb.

Direi che il meglio che stai per farla franca è intercettare la richiesta con Rack, qualcosa del genere.

In 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 

In config.ru, inserire questo prima della chiamata run <your app name>::Application

require 'raw_json' 
use Rack::RawJSON 
+0

sembra che tutto ciò che devi aggiungere a questa soluzione sia rilevare un determinato percorso, ad es. 'if request.path == '/ foo' e request.content_type = ~/application \/json/i' –

+0

Sì, è per questo che ho inserito un commento nel codice per testare request.path. –

+0

Non ho ancora provato questo, ma sembra abbastanza ragionevole di una soluzione, darò un colpo. – Macdiesel

1

L'overhead per analizzare il JSON da una singola richiesta è relativamente basso. Hai una ragione specifica per credere che l'elaborazione del JSON stia contribuendo a qualsiasi tipo di lentezza nell'elaborazione complessiva?

In caso contrario, si consiglia di lasciare questo come è finché non è possibile identificarlo come un problema.

Configurazione rotaie di non analizzare che JSON (sia attraverso una sorta di configurazione rack o in qualche altro metodo) creerà al timore che una via nella vostra applicazione che non viene gestita in uno standard Rails Way.

Eventualmente, potresti trovarti a dover eseguire una sorta di elaborazione di questi dati. O forse avrai bisogno di mettere una sorta di sicurezza di fronte ad esso. O forse vorrai loggarlo e metterlo in relazione con l'utente che lo ha inviato. E quando quel giorno arriverà tu (o qualcun altro nel tuo team) dovrai entrare e apportare modifiche a questa implementazione non standard.

Fare cose in modo non standard in un'implementazione di Rails può aumentare la complessità e il tempo necessari per la manutenzione del software. È anche una fonte comune di difetti poiché le persone hanno meno familiarità con l'elaborazione non standard.

Quindi, a meno che non si tratti di un problema reale, raccomanderei semplicemente di lasciare che i binari elaborino il JSON e poi semplicemente lo passino attraverso il normale modo Rails.

+1

Questo non risponde alla domanda. Sto cercando di non analizzare la risposta json in arrivo soprattutto per motivi di ottimizzazione. Il corpo JSON potrebbe potenzialmente essere un array con decine di migliaia di elementi e dover analizzare e scorrere su questo richiederà tempo e memoria dall'applicazione quando potrebbe/dovrebbe fare altre cose. Questa azione è semplicemente un passaggio per i dati. – Macdiesel

+0

NON è relativamente basso, Rails analizza l'intero input, filtra e registra TUTTI i parametri e il costo è ENORME quando si hanno a che fare con molte richieste da 100k. – lzap

1

può essere cotto in, ma guardando il codice:

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] 

Quindi, se si può organizzare per inviare un hash per questo inizializzatore, è possibile aggiungere o sostituire il valore predefinito. Non sei sicuro di consentire la rimozione, ma un metodo parser vuoto potrebbe funzionare.

Parser risposta qui: How do I initialize ActionDispatch::ParamsParser in Rails 3.1?

Codice è da actionpack-3.2.8/lib/action_dispatch/middleware/params_parser.rb