2011-12-14 8 views
16

Sto tentando di eseguire il debug di un problema in cui Rails non sta decodificando i dati POST JSON.Rails La richiesta JSON non viene analizzata correttamente nei parametri del post

I log del server mostrano:

2011-12-14T06:44:44+00:00 app[web.2]: Started POST 
2011-12-14T06:44:44+00:00 app[web.2]: Processing by PostsController#create as */* 
2011-12-14T06:44:44+00:00 app[web.2]: Parameters: {"{\"athlete_id\":\"\",\"known_as\":\"abc\",\"email\":\"[email protected]\",\"result\":\"112233\",\"rx\":false,\"mods\":\"thkjth\",\"notes\":\"\"}"=>nil, "affiliate_id"=>"testaffiliate", "wod_id"=>"12345"} 

Nota che la stringa JSON non viene analizzato - Rails consiste nell'assegnare come una chiave nella hash, che punta a un valore pari a zero. Qualcuno ha qualche idea prima di scrivere un before_filter che prova a JSON.parse tutte le chiavi params?

Non penso che questo sia rilevante poiché sto inviando e ricevendo dati okay, ma questo problema si verifica durante una richiesta CORS da IE (utilizzando XDomainRequest).

risposta

9
before_filter :fix_ie_params, only: [:create, :update] 

Per Thin:

def fix_ie_params 
    if request.format == '*/*' 
    # try to JSON decode in case of IE XDR 
    begin 

     params.merge! ActiveSupport::JSON.decode(request.body.string) 

    rescue Exception=>e 
     # todo: log exception 
    end 
    end 
end 

Per Unicorn e Phusion passeggeri:

def fix_ie_params 
    if request.format == '*/*' 
    # try to JSON decode in case of IE XDR 
    begin 

     request.body.rewind 
     params.merge! ActiveSupport::JSON.decode(request.body.read) 

    rescue Exception=>e 
     # todo: log exception 
    end 
    end 
end 
+0

Ho scoperto che facendo questo (su unicorno) ho il corpo della richiesta incluso nei parametri come chiave: '{'theBodyOfRequest' => nil,: controller => users,: action => 'update'}' A seconda di il tuo caso d'uso potrebbe causare problemi. Dato che è il primo parametro, ho aggiunto 'params.shift' per rimuoverlo. – Peter

+0

@collin, yeah - I dati che stavo facendo POSTing erano originariamente JSON '{: foo =>" bar "}' (che era stato modificato per l'invio) quindi i parametri del controller erano: '{" {\ "pippo \" => \ "bar \"} => nil, "controller" => "users" ...} ' – Peter

+0

@Peter, sembra il problema originale che ho descritto nella domanda, non è vero? il filtro è in esecuzione? – colllin

16

È possibile superare questo impostando l'intestazione Content-Type su "application/json". Puoi lasciare che il controller sappia cosa si aspetta restituire con l'intestazione Accept impostata su "application/json".

Il seguente comando con entrambe le intestazioni:

curl -d '{ "company": { "name": "acme", "address": "123 Carrot Street" } }' http://0.0.0.0:3000/mysite --header "Accept: application/json" --header "Content-Type: application/json" 

genera questo nei log:

Started POST "/mysite" for 127.0.0.1 at 2012-01-11 16:09:48 -0800 
    Processing by MyController#create as JSON 
    Parameters: {"company"=>{"name"=>"acme", "address"=>"123 Carrot Street"}, "wassup"=>{"company"=>{"name"=>"acme", "address"=>"123 Carrot Street"}, "controller"=>"wassup", "action"=>"create"}} 
Completed 200 OK in 5ms (Views: 2.0ms | ActiveRecord: 0.0ms) 

Questo comando con l'intestazione Accept:

curl -d '{ "company": { "name": "acme", "address": "123 Carrot Street" } }' http://0.0.0.0:3000/mysite --header "Accept: application/json" 

genera questi registri:

Started POST "/mysite" for 127.0.0.1 at 2012-01-11 16:07:26 -0800 
    Processing by MyController#create as JSON 
    Parameters: {"{ \"company\": { \"name\": \"acme\", \"address\": \"123 Carrot Street\" } }"=>nil} 
Completed 200 OK in 7ms (Views: 5.0ms | ActiveRecord: 0.0ms) 

E infine questo comando con l'intestazione Content-Type:

curl -d '{ "company": { "name": "acme", "address": "123 Carrot Street" } }' http://0.0.0.0:3000/mysite --header "Content-Type: application/json" 

genera questi registri:

Started POST "/mysite" for 127.0.0.1 at 2012-01-11 16:08:11 -0800 
    Processing by MyController#create as */* 
    Parameters: {"company"=>{"name"=>"acme", "address"=>"123 Carrot Street"}, "wassup"=>{"company"=>{"name"=>"acme", "address"=>"123 Carrot Street"}, "controller"=>"wassup", "action"=>"create"}} 
Completed 200 OK in 4ms (Views: 2.0ms | ActiveRecord: 0.0ms) 

Avviso i parametri analizzati e il messaggio di trasformazione cambiamento sottilmente con ogni tipo di intestazione.

+3

Grazie mille per la risposta! Sfortunatamente, con XDomainRequest non ho il controllo sulle intestazioni. (Vedere gli articoli 3 e 4 in [questo articolo] (http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx).) Quindi io penso che questa sia probabilmente la risposta corretta, ma non risolve il mio problema. Sai se esiste un modo per dire al controller di presumere che tutto sia una richiesta JSON? O almeno imposta il tipo di contenuto predefinito su JSON? – colllin

+1

Il json viene analizzato nel membro params (in rails 3.1) in params_parser.rb che contiene ActionDispatch :: ParamsParser ed è un pezzo di middleware. È possibile aggiungere un altro componente middleware che inferisce il tipo di richiesta in entrata e lo imposta in modo appropriato. Tuttavia, se lo farai, potresti anche mettere un po 'di logica nel controller per farlo per il tuo particolare codice e non alterare il resto della pila del middleware. – Grant

Problemi correlati