我有一个要求在特定的字符大小写发送HTTP头。我知道这是违反RFC的,但我有一个要求。如何使用http.get保存大小写?
http.get
似乎改变了我提供它的标题字典的情况。我怎样才能保留字符大小写?
我有一个要求在特定的字符大小写发送HTTP头。我知道这是违反RFC的,但我有一个要求。如何使用http.get保存大小写?
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
或子类的字符串来覆盖特定行为:
class StringWithIdentityDowncase < String
def downcase
self
end
end
custom_header_key = StringWithIdentityDowncase.new("X-miXEd-cASe")
+1我没有想过关闭'downcase'方法,但这就是基本上所做的。这让我的投票成为正确的答案。猴子补丁有太多的代码味道。 – 2012-01-15 10:01:14
我把你的帽子给你,先生!一个注意事项:我必须像使用该方法一样重写“大写”方法。 – codingFoo 2012-12-04 15:22:39
矿是一种做法,但我建议按照@yfeldblum的建议来做,只需短接downcase
即可找到需要自己的案例的标题键。
在净多个地方:: HTTP ::的HTTPHeader头获得折叠使用downcase
小写。
我认为改变这种行为是非常激烈的,但这会做到这一点。将它添加到源代码中,它将重新定义其中包含downcase
的HTTPHeader模块中的方法。
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都会失败。
接受的答案是行不通的。坦率地说,我怀疑它曾经做过,因为它看起来像也必须覆盖split and capitalize,我遵循该方法回几次提交,至少自2004年以来一直这样。
这是我的解决方案,在答案到this封闭的问题:
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
# >>
你是我的英雄! – 2015-05-19 14:49:14
FWIW,这不适用于Ruby .2.3。它非常接近,请参阅https://github.com/jnunemaker/httparty/issues/406 – 2017-03-07 21:33:53
它全部落入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
,你不需要重写整个网/ HTTP /头,净/ generic_request和网/ HTTP链。 这不是最好的解决方案,但它是我猜测的最简单的解决方案,猴子补丁的数量最少。
希望它有帮助。
约书亚脸颊的答案是伟大的,但它在工作了Ruby的2.3
此修改修复它:
class Net::HTTP::ImmutableHeaderKey
...
def to_s
caller.first.match(/capitalize/) ? self : @key
end
end
通常要求是(至少部分地)值得商榷。如果你的“要求”是违反HTTP规范,那么你应该辩论你的客户。事情**将一路走来,你将很难适应你介绍的每一个新组件。其中包括代理,负载均衡器,防火墙和Web服务器等内容。所有这些人都必须配合你的改变,这在每一种情况下都很难实现。你应该尝试找到另一种解决方案,否则你将忍受痛苦之后:) – 2012-01-15 09:02:24
我需要与违反rfc的第三方系统进行互操作。我可以做的不多。 – 2012-01-15 10:14:55
[修复所有系统](http://i.stack.imgur.com/UXBEb.jpg) – 2012-01-15 10:28:32