[英]Preserving case in HTTP headers with Ruby's Net:HTTP
Although the HTTP spec says that headers are case insensitive;尽管 HTTP 规范说标头不区分大小写; Paypal, with their new adaptive payments API require their headers to be case-sensitive. Paypal 及其新的自适应支付 API 要求其标头区分大小写。
Using the paypal adaptive payments extension for ActiveMerchant ( http://github.com/lamp/paypal_adaptive_gateway ) it seems that although the headers are set in all caps, they are sent in mixed case.使用 ActiveMerchant ( http://github.com/lamp/paypal_adaptive_gateway ) 的 paypal 自适应支付扩展似乎虽然标题设置为全部大写,但它们以混合大小写发送。
Here is the code that sends the HTTP request:这是发送 HTTP 请求的代码:
headers = {
"X-PAYPAL-REQUEST-DATA-FORMAT" => "XML",
"X-PAYPAL-RESPONSE-DATA-FORMAT" => "JSON",
"X-PAYPAL-SECURITY-USERID" => @config[:login],
"X-PAYPAL-SECURITY-PASSWORD" => @config[:password],
"X-PAYPAL-SECURITY-SIGNATURE" => @config[:signature],
"X-PAYPAL-APPLICATION-ID" => @config[:appid]
}
build_url action
request = Net::HTTP::Post.new(@url.path)
request.body = @xml
headers.each_pair { |k,v| request[k] = v }
request.content_type = 'text/xml'
proxy = Net::HTTP::Proxy("127.0.0.1", "60723")
server = proxy.new(@url.host, 443)
server.use_ssl = true
server.start { |http| http.request(request) }.body
(i added the proxy line so i could see what was going on with Charles - http://www.charlesproxy.com/ ) (我添加了代理行,所以我可以看到查尔斯发生了什么 - http://www.charlesproxy.com/ )
When I look at the request headers in charles, this is what i see:当我查看 charles 中的请求标头时,我看到的是:
X-Paypal-Application-Id ...
X-Paypal-Security-Password...
X-Paypal-Security-Signature ...
X-Paypal-Security-Userid ...
X-Paypal-Request-Data-Format XML
X-Paypal-Response-Data-Format JSON
Accept */*
Content-Type text/xml
Content-Length 522
Host svcs.sandbox.paypal.com
I verified that it is not Charles doing the case conversion by running a similar request using curl.我通过使用 curl 运行类似的请求来验证不是 Charles 进行大小写转换。 In that test the case was preserved.在那个测试中,这个案例被保留了下来。
The RFC does specify that header keys are case-insensitive , so unfortunately you seem to have hit an annoying requirement with the PayPal API. RFC 确实指定标头键不区分大小写,因此不幸的是,您似乎遇到了 PayPal API 令人讨厌的要求。
Net::HTTP is what is changing the case, although I'm surprised they're not all getting downcased: Net::HTTP 正在改变这种情况,尽管我很惊讶它们并没有全部被低估:
# File net/http.rb, line 1160
def []=(key, val)
unless val
@header.delete key.downcase
return val
end
@header[key.downcase] = [val]
end
"Sets the header field corresponding to the case-insensitive key." “设置与不区分大小写的键对应的头字段。”
As the above is a simple class it could be monkey-patched.由于上面是一个简单的类,它可以被猴子修补。 I will think further for a nicer solution.我会进一步考虑更好的解决方案。
Use following code to force case sensitive headers.使用以下代码强制区分大小写的标头。
class CaseSensitivePost < Net::HTTP::Post
def initialize_http_header(headers)
@header = {}
headers.each{|k,v| @header[k.to_s] = [v] }
end
def [](name)
@header[name.to_s]
end
def []=(name, val)
if val
@header[name.to_s] = [val]
else
@header.delete(name.to_s)
end
end
def capitalize(name)
name
end
end
Usage example:用法示例:
post = CaseSensitivePost.new(url, {myCasedHeader: '1'})
post.body = body
http = Net::HTTP.new(host, port)
http.request(post)
I got several issues with the code proposed by @kaplan-ilya because the Net::HTTP library tries to detect the post content-type, and the I ended up with 2 content-type and other fields repeated with different cases.我在@kaplan-ilya 提出的代码中遇到了几个问题,因为 Net::HTTP 库试图检测帖子内容类型,而我最终得到了 2 个内容类型和其他字段,这些字段在不同情况下重复。
So the code below should ensure than once a particular case has been choosen, it will stick to the same.所以下面的代码应该确保一旦选择了一个特定的案例,它就会坚持下去。
class Post < Net::HTTP::Post
def initialize_http_header(headers)
@header = {}
headers.each { |k, v| @header[k.to_s] = [v] }
end
def [](name)
_k, val = header_insensitive_match name
val
end
def []=(name, val)
key, _val = header_insensitive_match name
key = name if key.nil?
if val
@header[key] = [val]
else
@header.delete(key)
end
end
def capitalize(name)
name
end
def header_insensitive_match(name)
@header.find { |key, _value| key.match Regexp.new(name.to_s, Regexp::IGNORECASE) }
end
end
If you are still looking for an answer that works.如果您仍在寻找有效的答案。 Newer versions have introduced some changes to underlying capitalize
method by using to_s
.较新的版本通过使用to_s
对底层的capitalize
方法进行了一些更改。 Fix is to make the to_s
and to_str
return the self
so that the returned object is an instance of ImmutableKey
instead of the base string class.修复是让to_s
和to_str
返回self
以便返回的对象是ImmutableKey
的实例而不是基字符串类。
class ImmutableKey < String
def capitalize
self
end
def to_s
self
end
alias_method :to_str, :to_s
end
Ref: https://jatindhankhar.in/blog/custom-http-header-and-ruby-standard-library/参考: https : //jatindhankhar.in/blog/custom-http-header-and-ruby-standard-library/
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.