Sinatra controller méthode params à venir vide sur demande de JSON post

J'ai une application Sinatra et dans la plupart de mes contrôleurs json est entré et est repris automatiquement dans l'objet params. Cependant, j'ai une action de poste qui n'obtient pas les params du tout à moins que je joue un tour avec une méthode avant de tirer la demande.les paramètres du corps les analysent comme JSON et les fusionnent dans le hash des params.

voici le contrôleur, ainsi que la méthode du filtre:

before do
  if request.request_method == "POST"
    body_parameters = request.body.read
    params.merge!(JSON.parse(body_parameters))
  end
end


post '/locations/new' do
  content_type :json
  puts "params after post params method = #{params.inspect}"
  ... other code ...
end

la sortie que je vois est essentiellement que le les paramètres du contrôleur d'action sont là correctement. Cependant, si je commente l'appel avant les params sont vides.

l'avant lui-même se sent comme un piratage. Je les params de venir dans n'importe quoi...Je dois faire quelque chose de mal, mais je ne sais pas ce que c'est.

Toute aide serait grandement appréciée...

25
demandé sur jaydel 2012-08-26 20:23:36

2 réponses

pour répondre à cette question, nous allons d'abord devoir regarder quelques requêtes HTTP (qui ne sont pas plus que de simples" messages " 151920920; cela peut facilement être recréé à la main). Tout d'abord, que se passe-t-il lorsque vous soumettez un HTML normal <form> ? La requête POST ressemblera beaucoup à celle-ci (probablement avec quelques paramètres supplémentaires, mais nous n'avons pas besoin de nous en inquiéter pour le moment):

POST /submit-form HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 12

name=JohnDoe

tapant ce caractère par caractère (en remplaçant le /sample-form par n'importe quelle URL pour n'importe quelle action de forme, et le Host par votre IP ou nom d'hôte) sera la même chose que votre navigateur enverrait. La chose importante à savoir, c'est la syntaxe de paramètre: formname=formvalue . Sinatra interprète le corps de la requête POST dans le hash params en utilisant cette syntaxe! par conséquent, les demandes de JSON, étant essentiellement incompatible avec ce, sera et non apparaître dans le params hachage à cause de cela.

cependant, ce que vous faites dans votre bloc before montre la bonne solution. Alors que params de ce qui précède serait {'name' => 'JohnDoe'} , request.body.read retournera le corps original, name=JohnDoe .

en sachant cela, on peut en venir à comprendre pourquoi votre solution' hacky 'fonctionne: le corps original de la requête POST est interprété par JSON.parse , puis est inséré dans le vide params de hachage. La raison pour laquelle il semble hacky est parce que params est un intermédiaire inutile dans cet exemple. Le suivant devrait faire le travail:

post '/locations/new' do
    @json = JSON.parse(request.body.read)
    # @json now contains a hash of the submitted JSON content
end

cependant, une solution faisant appel à une meilleure pratique ne répondrait que si le contenu JSON était fourni, ou répondrait différemment si un formulaire standard était soumis. Comme le montre L'exemple ci-dessus de requête HTTP POST , un formulaire HTML est identifié avec le type MIME application/x-www-form-urlencoded , tandis que JSON est identifié avec application/json . Si vous voulez les détails sur la vérification du type MIME de la demande POST , consultez cette question avec quelques grandes réponses sur la façon de faire cela avec Sinatra!

32
répondu Kyle Lacy 2017-05-23 12:34:08

avait un problème similaire: Affichage JSON params de java à sinatra service

j'ai trouvé une meilleure solution pour y faire face, en ajoutant un middleware pour faire la même chose pour moi. J'ai utilisé du rack-contrib gem. Voici les changements que j'ai faits dans mon code:

EDIT: utiliser git pour obtenir la version spécifique, où il résout le problème lorsque le contenu est de type application/json;charset=UTF-8

Gemfile:

gem 'rack-contrib', git: 'git@github.com:rack/rack-contrib', ref: 'b7237381e412852435d87100a37add67b2cfbb63'

config.ru:

use Rack::PostBodyContentTypeParser

source: http://jaywiggins.com/2010/03/using-rack-middleware-to-parse-json /

12
répondu goyalankit 2017-05-23 12:34:08