Rails 所有用 Rails 写的网站,在参数后面加上?foo=%9g,都会直接返回一个 400,而且好像抓不住这个报错

ad583255925 · August 29, 2018 · Last by ad583255925 replied at August 30, 2018 · 2296 hits

我们的网站里会经常会出现一些参数编码不正确的请求,想抓住这个报错,然后比较友善的返回给请求方 控制器里加了

rescue_from Rack::QueryParser::InvalidParameterError do |ex|
    render_error("无效参数: #{ex.message}", 400)
end

在开发过程中,我造了一个这样不合法的请求

http://localhost:3000/enjar/coupons/12312312?foo=%9g

然而虽然确实返回了 400,但是我的日志并没有动,而且也没有文字 (无效参数:xxxx) 返回来,但是我关掉服务,确实变成了 404,求问一下,这个报错怎么抓

参数解析的中间件位置在 routing 前面,还没到达 controller,所以 controller 里捕获不到这个异常。

我知道一个方法是在前面插入中间件,参考 https://robots.thoughtbot.com/catching-json-parse-errors-with-custom-middleware

Reply to Rei

好像在 Rails5 里面不行了

提一个 pull request 就好了,应该是解析出问题的。

unescape 改成 URI.unescape 就好了。

https://github.com/rack/rack/pull/1292/files

本地测试,正常了。

Reply to jmmbite

我试了下好像没效果,还是抓不到这个错

Reply to ad583255925
Puma caught this error: Invalid query parameters: invalid %-encoding (%9g) (ActionController::BadRequest)
/usr/local/ruby/lib/ruby/gems/2.5.0/gems/rack-2.0.5/lib/rack/query_parser.rb:72:in `rescue in parse_nested_query'
/usr/local/ruby/lib/ruby/gems/2.5.0/gems/rack-2.0.5/lib/rack/query_parser.rb:60:in `parse_nested_query'
/usr/local/ruby/lib/ruby/gems/2.5.0/gems/rack-2.0.5/lib/rack/request.rb:468:in `parse_query'
/usr/local/ruby/lib/ruby/gems/2.5.0/gems/rack-2.0.5/lib/rack/request.rb:319:in `GET'

找到位置,调试就好了。程序要重启。

类似问题,传这种参数 ?datas[]=1&datas[id]=2,datas 既是 hash 又是数组,也报 400 , post 的时候报的是 404,Invalid or incomplete POST parameters. 看了下这里https://thomasleecopeland.com/2018/08/12/invalid-or-incomplete-post-parameters.html才发现自己的参数有问题

Reply to fangxing204

感觉 rack 有些参数不忽略,没处理好引起的问题。😂

改成: 多重类别参数,根据前后顺序,只取前面就好了,后面的一律忽略。 production 环境忽略,其它环境报错。

Puma caught this error: Invalid query parameters: expected Hash (got Array) for param `datas' (ActionController::BadRequest)
/usr/local/ruby/lib/ruby/gems/2.5.0/gems/rack-2.0.5/lib/rack/query_parser.rb:112:in `normalize_params'
/usr/local/ruby/lib/ruby/gems/2.5.0/gems/rack-2.0.5/lib/rack/query_parser.rb:67:in `block in parse_nested_query'
/usr/local/ruby/lib/ruby/gems/2.5.0/gems/rack-2.0.5/lib/rack/query_parser.rb:64:in `each'
/usr/local/ruby/lib/ruby/gems/2.5.0/gems/rack-2.0.5/lib/rack/query_parser.rb:64:in `parse_nested_query'

或者可以参考,php 的处理方式:

info.php?datas[]=1&datas[id]=2&datas[]=3

_REQUEST["datas"]   
Array
(
    [0] => 1
    [id] => 2
    [1] => 3
)

_GET["datas"]   
Array
(
    [0] => 1
    [id] => 2
    [1] => 3
)
Reply to jmmbite

我想问一下,你这个是控制器层面捕捉的错还是 puma 层面的

You need to Sign in before reply, if you don't have an account, please Sign up first.