如何使用http.get保留案例?

我需要在特定的字符大小写中发送HTTP标头。 我知道这是针对RFC的,但我有一个要求。

http.get似乎改变了我提供的头字典的情况。 我该如何保留角色?

根据Tin Man的回答, Net::HTTP库在您的自定义标头密钥(以及所有标头密钥)上调用#downcase ,这里有一些其他选项不会修补整个Net::HTTP

你可以试试这个:

 custom_header_key = "X-miXEd-cASe" def custom_header_key.downcase self end 

要避免清除方法缓存,请将上述结果存储在类级别常量中:

 custom_header_key = "X-miXEd-cASe" def custom_header_key.downcase self end CUSTOM_HEADER_KEY = custom_header_key 

或子类String以覆盖该特定行为:

 class StringWithIdentityDowncase < String def downcase self end end custom_header_key = StringWithIdentityDowncase.new("X-miXEd-cASe") 

接受的答案不起作用。 坦率地说,我怀疑它曾经做过,因为看起来它不得不覆盖拆分和大写 ,我跟着那个方法做了几次提交,至少自2004年以来就是这样。

这是我的解决方案,回答这个封闭的问题:

 require 'net/http' class Net::HTTP::ImmutableHeaderKey attr_reader :key def initialize(key) @key = key end def downcase self end def capitalize self end def split(*) [self] end def hash key.hash end def eql?(other) key.eql? other.key.eql? end def to_s key end end 

现在,您需要确保始终使用此类的实例作为键。

 request = Net::HTTP::Get.new('/') user_key = Net::HTTP::ImmutableHeaderKey.new("user") request[user_key] = "James" require 'stringio' StringIO.new.tap do |output| request.exec output, 'ver', 'path' puts output.string end # >> GET path HTTP/ver # >> Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3 # >> Accept: */* # >> User-Agent: Ruby # >> user: James # >> 

我是一种方法,但我建议按照@yfeldblum的建议来做这件事,只需简单地为需要单独保留案例的标题键短路。


在Net :: HTTP :: HTTPHeader中的多个位置,标题使用downcase折叠为小写。

我认为改变这种行为非常激烈,但这样做会有所改变。 将其添加到您的源中,它将重新定义HTTPHeader模块中具有downcase的方法。

 module HTTPHeader def initialize_http_header(initheader) @header = {} return unless initheader initheader.each do |key, value| warn "net/http: warning: duplicated HTTP header: #{key}" if key?(key) and $VERBOSE @header[key] = [value.strip] end end def [](key) a = @header[key] or return nil a.join(', ') end def []=(key, val) unless val @header.delete key return val end @header[key] = [val] end def add_field(key, val) if @header.key?(key) @header[key].push val else @header[key] = [val] end end def get_fields(key) return nil unless @header[key] @header[key].dup end def fetch(key, *args, &block) #:yield: +key+ a = @header.fetch(key, *args, &block) a.kind_of?(Array) ? a.join(', ') : a end # Removes a header field. def delete(key) @header.delete(key) end # true if +key+ header exists. def key?(key) @header.key?(key) end def tokens(vals) return [] unless vals vals.map {|v| v.split(',') }.flatten\ .reject {|str| str.strip.empty? }\ .map {|tok| tok.strip } end end 

我认为这是一种蛮力的方式来实现它,但没有别的更优雅跳跃到脑海。

虽然这应该解决使用Net :: HTTP的任何Ruby库的问题,但对于使用Curl或libcurl的任何gem,它可能会失败。

Joshua Cheek的答案很棒,但它在Ruby 2.3中已经完成了

此修改修复它:

 class Net::HTTP::ImmutableHeaderKey ... def to_s caller.first.match(/capitalize/) ? self : @key end end 

这一切都落入了net / generic_request#write_header。 你可以修补代码

 # 'net/generic_request' line 319 def write_header(sock, ver, path) customheaders = { "My-Custom-Header" => "MY-CUSTOM-HEADER", "Another-Custom-Header" => "aNoThErCuStOmHeAdEr" } buf = "#{@method} #{path} HTTP/#{ver}\r\n" each_capitalized do |k,v| customheaders.key?(k) ? kk = customheaders[k] : kk = k buf << "#{kk}: #{v}\r\n" end buf << "\r\n" sock.write buf end 

并且您不需要重写整个net / http / header,net / generic_request和net / http链。 这不是最好的解决方案,但它是我猜的最简单的解决方案,并且修补猴子的数量最少。

希望能帮助到你。