Rack::Request - how do I get all headers?

后端 未结 3 813
醉话见心
醉话见心 2020-12-09 02:26

The title is pretty self-explanatory. Is there any way to get the headers (except for Rack::Request.env[])?

相关标签:
3条回答
  • 2020-12-09 02:44

    The HTTP headers are available in the Rack environment passed to your app:

    HTTP_ Variables: Variables corresponding to the client-supplied HTTP request headers (i.e., variables whose names begin with HTTP_). The presence or absence of these variables should correspond with the presence or absence of the appropriate HTTP header in the request.

    So the HTTP headers are prefixed with "HTTP_" and added to the hash.

    Here's a little program that extracts and displays them:

    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
    

    When I run this, in addition to the HTTP headers as shown by Chrome or Firefox, there is a "VERSION: HTPP/1.1" (i.e. an entry with key "HTTP_VERSION" and value "HTTP/1.1" is being added to the env hash).

    0 讨论(0)
  • 2020-12-09 02:59

    Like @Gavriel's answer, but using transform_keys (simpler):

    class Request
      def headers
        env.select { |k,v| k.start_with? 'HTTP_'}.
          transform_keys { |k| k.sub(/^HTTP_/, '').split('_').map(&:capitalize).join('-') }
      end
    end
    

    You can even make it so lookups still work even if the case is different:

      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
    

    So for example, even if headers normalizes the keys so it returns this:

    {
      Dnt: '1',
      Etag: 'W/"ec4454af5ae1bacff1afc5a06a2133f4"',
      'X-Xss-Protection': '1; mode=block',
    }
    

    you can still look up headers using the more natural/common names for these headers:

    headers['DNT']
    headers['ETag']
    headers['X-XSS-Protection']
    
    0 讨论(0)
  • 2020-12-09 03:07

    Based on @matt's answer, but this really gives you the request headers in a hash as requested in the question:

    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]
    

    Depending on what key convention you prefer you might want to use something else instead of :capitalize.

    0 讨论(0)
提交回复
热议问题