【发布时间】:2011-09-13 03:31:43
【问题描述】:
标题是不言自明的。有什么方法可以获取标题(Rack::Request.env[] 除外)?
【问题讨论】:
标签: ruby http http-headers rack
标题是不言自明的。有什么方法可以获取标题(Rack::Request.env[] 除外)?
【问题讨论】:
标签: ruby http http-headers rack
HTTP 标头在传递给您的应用的Rack environment 中可用:
HTTP_变量:对应于客户端提供的 HTTP 请求标头的变量(即名称以 HTTP_ 开头的变量)。这些变量的存在与否应该与请求中相应 HTTP 标头的存在与否相对应。
因此 HTTP 标头以“HTTP_”为前缀并添加到哈希中。
这是一个提取并显示它们的小程序:
require 'rack'
app = Proc.new do |env|
headers = env.select {|k,v| k.start_with? 'HTTP_'}
.collect {|key, val| [key.sub(/^HTTP_/, ''), val]}
.collect {|key, val| "#{key}: #{val}<br>"}
.sort
[200, {'Content-Type' => 'text/html'}, headers]
end
Rack::Server.start :app => app, :Port => 8080
当我运行此程序时,除了 Chrome 或 Firefox 显示的 HTTP 标头外,还有一个“VERSION:HTPP/1.1”(即一个带有键“HTTP_VERSION”和值“HTTP/1.1”的条目正在添加到 env 哈希)。
【讨论】:
env :)。我不喜欢的是替换了一些字符的大写名称。好吧,我想我将不得不摆脱它......
- 正在更改为 _。我想这是为了与 CGI 保持兼容(环境变量不能包含-)。但 response 标头不应该受到影响。
基于@matt 的回答,但这确实为您提供了问题中所要求的散列中的请求标头:
headers = Hash[*env.select {|k,v| k.start_with? 'HTTP_'}
.collect {|k,v| [k.sub(/^HTTP_/, ''), v]}
.collect {|k,v| [k.split('_').collect(&:capitalize).join('-'), v]}
.sort
.flatten]
根据您喜欢的键约定,您可能想要使用其他内容而不是 :capitalize。
【讨论】:
像@Gavriel 的回答,但使用transform_keys(更简单):
class Request
def headers
env.select { |k,v| k.start_with? 'HTTP_'}.
transform_keys { |k| k.sub(/^HTTP_/, '').split('_').map(&:capitalize).join('-') }
end
end
您甚至可以做到这一点,即使大小写不同,查找仍然有效:
def headers
env.
select { |k,v| k.start_with? 'HTTP_'}.
transform_keys { |k| k.sub(/^HTTP_/, '').split('_').map(&:capitalize).join('-') }.
sort.to_h.
tap do |headers|
headers.define_singleton_method :[] do |k|
super(k.split(/[-_]/).map(&:capitalize).join('-'))
end
end
end
例如,即使headers 规范化了键,它也会返回:
{
Dnt: '1',
Etag: 'W/"ec4454af5ae1bacff1afc5a06a2133f4"',
'X-Xss-Protection': '1; mode=block',
}
您仍然可以使用这些标头的更自然/通用名称来查找标头:
headers['DNT']
headers['ETag']
headers['X-XSS-Protection']
【讨论】:
'Dnt': '1'而不是Dnt: '1'吗?
Dnt: 是正确的。使用 'Dnt': 是 JSON 而不是 ruby。
'Dnt': '1', 这里的键是从头到尾的字符串。大写的文字表示 Ruby 中的常量。
'Dnt': 解析为符号 :Dnt。如果你想要字符串键,你需要{ 'Dnt' => '1' }。这将告诉您'Dnt': 是一个符号{ 'Dnt': '1' }.each_pair { |key, value| puts key.inspect }。
Dnt='Knock';{ 'Dnt': 1, 'Dnt' => 2, Dnt => 3 } 的计算结果为 {:Dnt=>1, "Dnt"=>2, "Knock"=>3}。