如何让 Sinatra 正确处理其中包含数组的 JSON 请求?
How can you get Sinatra to properly process a JSON request that has an array in it?
我正在 POST 与 javascript 一起使用 Sinatra,如下所示:
var payload = {
cart: [
{qty: 1, product: { name: 'baseball' },
{qty: 3, product: { name: 'soccer' }
]
}
$.post("/endpoint", payload, submit)
从 Sinatra 中,params 产生以下内容:
{"cart" => {
"0"=>{"qty"=>"1", "product"=> {"name"=>"baseball"} },
"1"=>{"qty"=>"3", "product"=> {"name"=>"soccer"} }
}}
如何让参数变成这样?
{
:cart => [
{ :qty => 1, :product => { :name => "baseball" } },
{ :qty => 3, :product => { :name => "soccer" } },
]
}
我前一段时间遇到了同样的问题,我创建了 gem
这样做(任何其他简化深层嵌套结构的东西 iteration/mapping)。检查 Iteraptor
.
json = {"cart" => {
"0"=>{"qty"=>"1", "product"=> {"name"=>"baseball"} },
"1"=>{"qty"=>"3", "product"=> {"name"=>"soccer"} }
}}
json.aplanar.recoger(symbolize_keys: true)
#⇒ {:cart=>[
# {:qty=>"1", :product=>{:name=>"baseball"}},
# {:qty=>"3", :product=>{:name=>"soccer"}}]}
您可以查看源代码,了解手动实现所需结果并非易事。
cart_params = {"cart" => {
"0"=>{"qty"=>"1", "product"=> {"name"=>"baseball"} },
"1"=>{"qty"=>"3", "product"=> {"name"=>"soccer"} }
}}
> hash = JSON.parse(cart_params.to_json, symbolize_names: true)
> hash[:cart] = hash[:cart].values
> hash
#=> {
# :cart=>[
# {:qty=>"1", :product=>{:name=>"baseball"}},
# {:qty=>"3", :product=>{:name=>"soccer"}}
# ]
# }
要解决这个问题,您首先需要了解的是您目前不是发送JSON。 JQuery 正在使用 param()
function 将数据序列化为 application/x-www-form-urlencoded
,并正在发送(它实际上是发送此的转义版本):
cart[0][qty]=1&cart[0][product][name]=baseball&cart[1][qty]=3&cart[1][product][name]=soccer
param()
的文档有以下注释:
Note: Because some frameworks have limited ability to parse serialized arrays, developers should exercise caution when passing an obj argument that contains objects or arrays nested within another array.
和
Note: Because there is no universally agreed-upon specification for param strings, it is not possible to encode complex data structures using this method in a manner that works ideally across all languages supporting such input. Use JSON format as an alternative for encoding complex data instead.
这就是您面临的问题。 Sinatra 尝试将表单 urlencoded 数据解析为 Ruby 数据结构,但它需要一种不同的格式。它使用 Rack::Utils.parse_nested_query
生成您从该查询字符串中看到的参数。
正如 jQuery 文档所建议的那样,解决方案是将数据发送为 JSON。这将确保数据结构不会在浏览器和服务器之间被破坏。
第一步是让浏览器发送JSON。您可以使用 post()
函数的另一种形式来执行此操作,指定内容类型并将数据转换为 JSON 字符串:
$.post({url: "/endpoint", data: JSON.stringify(payload), contentType: "application/json", success: submit});
默认情况下,Sinatra 将忽略任何内容类型为 JSON 的请求,并将处理留给您,因此解决方案的另一半是让 Sinatra 解析 JSON,并可选择填充参数哈希。
一种方法是使用 Rack contrib 模块 PostBodyContentTypeParser
。只需将以下内容添加到您的应用程序(您需要先安装 rack-contrib
gem):
require 'rack/contrib/post_body_content_type_parser'
use Rack::PostBodyContentTypeParser
现在,任何具有 JSON 内容类型的 POST 或 PUT 请求都将被解析,并将内容添加到参数哈希中。然而,当前发布的版本没有将键转换为符号的方法(master 中有一个更改允许这样做,但尚未发布)所以它会产生类似的东西:
{
"cart"=>[
{"qty"=>1, "product"=>{"name"=>"baseball"}},
{"qty"=>3, "product"=>{"name"=>"soccer"}}
]
}
如果你想获得符号化的钥匙,你将不得不“手动”。在你的路线中你可以添加:
request.body.rewind # Just in case some middleware has already read it
data = JSON.parse(request.body.read, symbolize_names: true)
(如果需要,您可以将其添加到 before
过滤器,只需添加一个检查内容类型实际上是 JSON)。
这不会将数据添加到 params
哈希,但会以您正在查找的形式提供数据。
我正在 POST 与 javascript 一起使用 Sinatra,如下所示:
var payload = {
cart: [
{qty: 1, product: { name: 'baseball' },
{qty: 3, product: { name: 'soccer' }
]
}
$.post("/endpoint", payload, submit)
从 Sinatra 中,params 产生以下内容:
{"cart" => {
"0"=>{"qty"=>"1", "product"=> {"name"=>"baseball"} },
"1"=>{"qty"=>"3", "product"=> {"name"=>"soccer"} }
}}
如何让参数变成这样?
{
:cart => [
{ :qty => 1, :product => { :name => "baseball" } },
{ :qty => 3, :product => { :name => "soccer" } },
]
}
我前一段时间遇到了同样的问题,我创建了 gem
这样做(任何其他简化深层嵌套结构的东西 iteration/mapping)。检查 Iteraptor
.
json = {"cart" => {
"0"=>{"qty"=>"1", "product"=> {"name"=>"baseball"} },
"1"=>{"qty"=>"3", "product"=> {"name"=>"soccer"} }
}}
json.aplanar.recoger(symbolize_keys: true)
#⇒ {:cart=>[
# {:qty=>"1", :product=>{:name=>"baseball"}},
# {:qty=>"3", :product=>{:name=>"soccer"}}]}
您可以查看源代码,了解手动实现所需结果并非易事。
cart_params = {"cart" => {
"0"=>{"qty"=>"1", "product"=> {"name"=>"baseball"} },
"1"=>{"qty"=>"3", "product"=> {"name"=>"soccer"} }
}}
> hash = JSON.parse(cart_params.to_json, symbolize_names: true)
> hash[:cart] = hash[:cart].values
> hash
#=> {
# :cart=>[
# {:qty=>"1", :product=>{:name=>"baseball"}},
# {:qty=>"3", :product=>{:name=>"soccer"}}
# ]
# }
要解决这个问题,您首先需要了解的是您目前不是发送JSON。 JQuery 正在使用 param()
function 将数据序列化为 application/x-www-form-urlencoded
,并正在发送(它实际上是发送此的转义版本):
cart[0][qty]=1&cart[0][product][name]=baseball&cart[1][qty]=3&cart[1][product][name]=soccer
param()
的文档有以下注释:
Note: Because some frameworks have limited ability to parse serialized arrays, developers should exercise caution when passing an obj argument that contains objects or arrays nested within another array.
和
Note: Because there is no universally agreed-upon specification for param strings, it is not possible to encode complex data structures using this method in a manner that works ideally across all languages supporting such input. Use JSON format as an alternative for encoding complex data instead.
这就是您面临的问题。 Sinatra 尝试将表单 urlencoded 数据解析为 Ruby 数据结构,但它需要一种不同的格式。它使用 Rack::Utils.parse_nested_query
生成您从该查询字符串中看到的参数。
正如 jQuery 文档所建议的那样,解决方案是将数据发送为 JSON。这将确保数据结构不会在浏览器和服务器之间被破坏。
第一步是让浏览器发送JSON。您可以使用 post()
函数的另一种形式来执行此操作,指定内容类型并将数据转换为 JSON 字符串:
$.post({url: "/endpoint", data: JSON.stringify(payload), contentType: "application/json", success: submit});
默认情况下,Sinatra 将忽略任何内容类型为 JSON 的请求,并将处理留给您,因此解决方案的另一半是让 Sinatra 解析 JSON,并可选择填充参数哈希。
一种方法是使用 Rack contrib 模块 PostBodyContentTypeParser
。只需将以下内容添加到您的应用程序(您需要先安装 rack-contrib
gem):
require 'rack/contrib/post_body_content_type_parser'
use Rack::PostBodyContentTypeParser
现在,任何具有 JSON 内容类型的 POST 或 PUT 请求都将被解析,并将内容添加到参数哈希中。然而,当前发布的版本没有将键转换为符号的方法(master 中有一个更改允许这样做,但尚未发布)所以它会产生类似的东西:
{
"cart"=>[
{"qty"=>1, "product"=>{"name"=>"baseball"}},
{"qty"=>3, "product"=>{"name"=>"soccer"}}
]
}
如果你想获得符号化的钥匙,你将不得不“手动”。在你的路线中你可以添加:
request.body.rewind # Just in case some middleware has already read it
data = JSON.parse(request.body.read, symbolize_names: true)
(如果需要,您可以将其添加到 before
过滤器,只需添加一个检查内容类型实际上是 JSON)。
这不会将数据添加到 params
哈希,但会以您正在查找的形式提供数据。