Search code examples
pythonflaskpython-requestshttp-headers

Can flask send duplicate headers in a response?


I would like my flask app to set multiple headers with the same key and different values, like this:

Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers

I already know that this is equivalent to a single header whose value is a comma-separated list (only for headers that support a list value, of course), but I would rather do it as above. But headers are stored in a dict, so I can't just add a duplicate key.

I am also aware of this question and answer, which says that the requests module cannot send multiple headers with the same key. But that question is about requests, and flask sometimes has extra goodies; also the question is over seven years old, and things happen.

Is that answer up to date? Does it also apply to flask?


Solution

  • Request Headers

    You can have duplicated header keys, however, Flask turns them into a text, values separated with comma,

    The easiest example would be:

    from flask import Flask, request
    
    app = Flask(__name__)
    
    @app.route('/')
    def index():
        print(request.headers)
        return "Hello"
    

    with the following curl: curl http://127.0.0.1:5000 -H 'X-HEADER: 1' -H 'X-HEADER: 2'

    Flask would print X-Header: 1,2 for X-Header in headers Also, you can get a list of values using request.headers.getlist('X-Header'), but it still sticks the values together and returns a list with only one element. ['1,2']

    The request.headers is an instance of werkzeug.datastructures.EnvironHeaders

    Surely you can modify it to use your own headers class. You can inherit flask.Request class and create your own request instance with customized Headers class

    You can read more about EnvironHeaders here: https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.EnvironHeaders

    Response Headers

    About the response headers:

    All flask responses come from flask.Response class.

    You can return your response from your view like:

    from flask import Flask, Response
    
    app = Flask(__name__)
    
    @app.route('/')
    def index():
        return Response('Hello', headers={'X-Headers': [1, 2]})
    

    You can test this with the following curl: curl http://127.0.0.1:5000 -vvv I added -vvv to increase verbosity and show Headers

    The following will show up in response headers:

    < X-Headers: 1
    < X-Headers: 2
    

    Also if you don't want to use Response class, You can return multiple values from a view

    @app.route('/')
    def index():
        return '<h1>Hello!</h1>', 200, {'X-Headers': [1, 2]}
    

    The first value is the body of your response, the second one is the status code, and the last one is the headers of your response.