在 rails 操作中解析 windows-1252 参数

问题描述

我的 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