Rack::Request - как мне получить все заголовки?

Название довольно очевидно. Есть ли способ получить заголовки (кроме Rack::Request.env[])?

2 ответа

Решение

Заголовки HTTP доступны в среде Rack и передаются вашему приложению:

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

Когда я запускаю это, в дополнение к заголовкам HTTP, как показано в Chrome или Firefox, появляется "VERSION: HTPP/1.1" (т. Е. В env добавляется запись с ключом "HTTP_VERSION" и значением "HTTP/1.1"). хэш).

На основании ответа @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]

В зависимости от того, какое ключевое соглашение вы предпочитаете, вы можете использовать что-то другое вместо: прописные.

Как и ответ @ Гавриила, но используя 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']
Другие вопросы по тегам