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

Parse windows-1252 param in rails action

我的 API 正在接收一个调用,该调用在 POST 正文中包含 windows-1252 编码数据。 在 rails 6.0.3 中,这显然有效。但是 rails 6.1.1 抛出 ActionController::BadRequest (Invalid request parameters: Invalid encoding for parameter.

编辑:我无法将来自第三方的调用更改为 UTF-8。所以,我的 API 必须接受 windows-1252 编码。

下面是模拟此调用的片段:

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 中的 'charset' 参数,这可能会起作用。但是,这有一个缺点,它会应用于所有调用,而不仅仅是 dummy#create 端点。

由于最近引入了这种行为(我假设是在 rail 6.1 中),现在有更好的方法来处理这个问题吗?

这里的解决方案,为每个参数添加param_encoding like document https://api.rubyonrails.org/classes/ActionController/ParameterEncoding/ClassMethods.html

param_encoding :create, :last_name, Encoding::ASCII_8BIT
param_encoding :create, :first_name, Encoding::ASCII_8BIT