停止Ruby HTTP请求修改标头名称

6

我正在使用Ruby进行HTTP请求:

  http = Net::HTTP.new(uri.host, uri.port)
  req = Net::HTTP::Post.new(uri.path)
  req.body = payload
  req['customeheader'] = 'xxxxxxxxx'
  http.set_debug_output $stdout

我已开启调试模式,当请求被提交时,我可以看到头部信息被提交为:

  Customheader: xxxxxxxxx

有没有办法阻止这种情况发生?我正在向第三方服务器发布内容,但是因为头部名称不正确而出现错误 - 它期望的是customheader:。请问该怎么做?
4个回答

14

虽然可以通过猴子补丁(monkey patch)Net::HTTPHeader和Net:HTTPGenericRequest来去除downcase和capitalize,但我发现了一种不同的方法,它允许选择性大小写敏感,而不是强制所有东西。

解决方案:

class CaseSensitiveString < String
    def downcase
        self
    end
    def capitalize
        self
    end
end

使用CaseSensitiveString.new('keyname')来创建区分大小写的键。对于其他键,使用字符串/符号以保持现有行为。这比猴子补丁简单得多,并且与rest-client库以及Net :: HTTP良好地配合使用。


1
这就是为什么 Ruby 如此棒。 - Carson Reinke
我看到这个解决方案不适用于ruby-2.3.0。然而,较低版本的工作正常。 - ArjunUrs

6
根据HTTP规范(RFC 2616),头字段名称不区分大小写。因此,第三方服务器存在破损的实现。
如果真的需要,您可以对Net::HTTP进行猴子补丁以保留大小写,因为它在存储字段名称时会将其转换为小写,然后使用首字母大写的方式进行写入。
这是您使用的存储方法(Net::HTTPHeader#[]=):
# File net/http.rb, line 1160
    def []=(key, val)
      unless val
        @header.delete key.downcase
        return val
      end
      @header[key.downcase] = [val]
    end

这里是写入头部的地方(Net::HTTPGenericRequest#write_header):

# File lib/net/http.rb, line 2071
    def write_header(sock, ver, path)
      buf = "#{@method} #{path} HTTP/#{ver}\r\n"
      each_capitalized do |k,v|
        buf << "#{k}: #{v}\r\n"
      end
      buf << "\r\n"
      sock.write buf
    end

这可能是你需要重写的唯一方法,但我不确定。


谢谢 - 我没有考虑到那个。顺便提一下,只需要在这种特定情况下修补write_header即可。 - probably at the beach

5

在之前的回答基础上,以下内容适用于Ruby 2.3:

class CaseSensitiveString < String
  def downcase
    self
  end

  def capitalize
    self
  end

  def to_s
    self
  end
end

to_s方法需要被添加,因为从2.3版本开始,HTTP::Headercapitalize方法会对每个header调用to_s


你需要小心,如果你使用这个解决方案来执行 req["Content-Type"] 操作,你不会覆盖 Ruby 设置的 "content-type"。 - Stephen

0
require 'net/http'
require 'uri'

# monkey patching inorder to suppress header hijacking by net/http, RFC -> headers are case insensitive
# File lib/net/http/header.rb, line 220, ruby 3.1.2

# def capitalize(name)
#   name.to_s.split(/-/).map {|s| s.capitalize }.join('-')
# end

class CustomGet < Net::HTTP::Get
  def capitalize(name)
    name
  end
end

uri = URI.parse('https://example.com')
request = CustomGet.new(uri)

headers = { 'custom-header': 'value' }

headers.each do |header, value|
  request[header] = value
end

req_options = {
  use_ssl: uri.scheme == 'https'
}

response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
  http.request(request)
end

p response.code
p response.body

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接