2012-01-14 44 views
3

我有一个要求在特定的字符大小写发送HTTP头。我知道这是违反RFC的,但我有一个要求。如何使用http.get保存大小写?

http.get似乎改变了我提供它的标题字典的情况。我怎样才能保留字符大小写?

+0

通常要求是(至少部分地)值得商榷。如果你的“要求”是违反HTTP规范,那么你应该辩论你的客户。事情**将一路走来,你将很难适应你介绍的每一个新组件。其中包括代理,负载均衡器,防火墙和Web服务器等内容。所有这些人都必须配合你的改变,这在每一种情况下都很难实现。你应该尝试找到另一种解决方案,否则你将忍受痛苦之后:) – 2012-01-15 09:02:24

+0

我需要与违反rfc的第三方系统进行互操作。我可以做的不多。 – 2012-01-15 10:14:55

+1

[修复所有系统](http://i.stack.imgur.com/UXBEb.jpg) – 2012-01-15 10:28:32

回答

13

根据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") 
+0

+1我没有想过关闭'downcase'方法,但这就是基本上所做的。这让我的投票成为正确的答案。猴子补丁有太多的代码味道。 – 2012-01-15 10:01:14

+1

我把你的帽子给你,先生!一个注意事项:我必须像使用该方法一样重写“大写”方法。 – codingFoo 2012-12-04 15:22:39

2

矿是一种做法,但我建议按照@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都会失败。

5

接受的答案是行不通的。坦率地说,我怀疑它曾经做过,因为它看起来像也必须覆盖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 
# >> 
+0

你是我的英雄! – 2015-05-19 14:49:14

+0

FWIW,这不适用于Ruby .2.3。它非常接近,请参阅https://github.com/jnunemaker/httparty/issues/406 – 2017-03-07 21:33:53

0

它全部落入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链。 这不是最好的解决方案,但它是我猜测的最简单的解决方案,猴子补丁的数量最少。

希望它有帮助。

1

约书亚脸颊的答案是伟大的,但它在工作了Ruby的2.3

此修改修复它:

class Net::HTTP::ImmutableHeaderKey 
    ... 

    def to_s 
    caller.first.match(/capitalize/) ? self : @key 
    end 
end 
相关问题