问题描述
我的 API 正在接收一个调用,该调用在 POST 正文中包含 Windows-1252 编码数据。 在 rails 6.0.3 中,这显然有效。但是 rails 6.1.1 抛出 ActionController::BadRequest (Invalid request parameters: Invalid encoding for parameter.
require 'net/http'
require 'uri'
uri = URI.parse("http://localhost:3030/dummy/create")
request = Net::HTTP::Post.new(uri)
request.content_type = "application/x-www-form-urlencoded"
# Rack::QueryParser::InvalidParameterError: Invalid encoding for parameter:
#G�bor
name = "Gábor".encode("windows-1252","utf-8")
request.body = "last_name=#{name}&first_name=Sam&charset=windows-1252"
response = Net::HTTP.start(uri.hostname,uri.port,nil) do |http|
http.request(request)
end
# 400
pp response.code
并且在服务器端,dummy#create
操作永远不会到达,它会以
Started POST "/dummy/create" for 127.0.0.1 at 2021-02-06 17:14:12 +0100
ActionController::BadRequest (Invalid request parameters: Invalid encoding for parameter: G�bor):
actionpack (6.1.1) lib/action_dispatch/request/utils.rb:39:in `check_param_encoding'
actionpack (6.1.1) lib/action_dispatch/request/utils.rb:34:in `block in check_param_encoding'
actionpack (6.1.1) lib/action_dispatch/request/utils.rb:34:in `each_value'
actionpack (6.1.1) lib/action_dispatch/request/utils.rb:34:in `check_param_encoding'
actionpack (6.1.1) lib/action_dispatch/http/request.rb:403:in `block in POST'
rack (2.2.3) lib/rack/request.rb:69:in `fetch'
rack (2.2.3) lib/rack/request.rb:69:in `fetch_header'
actionpack (6.1.1) lib/action_dispatch/http/request.rb:398:in `POST'
actionpack (6.1.1) lib/action_dispatch/http/parameters.rb:55:in `parameters'
...
我发现我可以注册一个中间件来拦截这种调用,如Rails/Rack: "ArgumentError: invalid %-encoding" for POST data
中所述然后中间件将检查 POST 中的“字符集”参数,这可能会起作用。但是,这有一个缺点,它适用于所有调用,而不仅仅是 dummy#create
端点。
自从最近引入了这种行为(我假设在 6.1 轨道中),现在有没有更好的方法来处理这个问题?
解决方法
这里的解决方案,为文档https://api.rubyonrails.org/classes/ActionController/ParameterEncoding/ClassMethods.html等每个参数添加param_encoding
param_encoding :create,:last_name,Encoding::ASCII_8BIT
param_encoding :create,:first_name,Encoding::ASCII_8BIT