一尘不染

Sinatra控制器params方法在JSON发布请求中变为空

json

我有一个Sinatra应用程序,并且在我的大多数控制器中,json都会传入并在params对象中自动获取。但是,除非我用before方法来拉取request.body参数,否则我将获得一个根本不获取参数的后期操作.body参数将它们解析为JSON并将它们合并到params哈希中。

这是控制器以及filter方法:

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

我看到的输出基本上是,控制器操作中的参数实际上正确地位于其中。但是,如果我注释掉before调用,则参数为空。

之前本身感觉就像是黑客。我希望这些参数无论如何都会出现…我必须在那里做错什么,但我不知道那是什么。

任何帮助将不胜感激…


阅读 207

收藏
2020-07-27

共1个答案

一尘不染

为了回答这个问题,我们首先必须查看一些HTTP请求(仅是简单的telnet“消息”;可以很容易地手动创建)。首先,提交普通的HTML会发生什么<form>?该POST请求看起来将与此非常相似(可能带有一些额外的参数,但是我们现在不必担心这一点):

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

name=JohnDoe

逐个字符地键入该字符(用/sample-form任何形式操作的URL
替换URL,并Host用您的IP或主机名替换该字符)将与您的浏览器发送的内容相同。要学习的重要内容是参数语法:formname=formvalue
Sinatra 使用此语法将POST请求的内容解释为params哈希!因此,与此基本不兼容的JSON请求将因此 不会
显示在params哈希中。

但是,您在before街区中所做的事情显示了正确的解决方案。虽然params从上面将是{'name' => 'JohnDoe'}request.body.read将返回原始主体,name=JohnDoe

知道了这一点,就可以理解为什么您的“
hacky”解决方案起作用了:POST请求的原始主体由解释JSON.parse,然后插入到空params哈希中。看起来很笨拙的原因是因为params在此示例中是不必要的中间人。以下应完成此工作:

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

但是,采用更好做法的解决方案要么仅在提供JSON内容时响应,要么在提交标准表单时做出不同响应。如上述示例HTTP
POST请求所示,HTML表单使用application/x-www-form- urlencodedMIME类型标识,而JSON使用标识application/json

2020-07-27