简体   繁体   中英

Add headers in a Flask app with unicode_literals

Adding headers with unicode_literals enabled seems to fail with Nginx, uWSGI and a simple Flask app:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from flask import Flask, make_response

app = Flask('test')

@app.route('/')
def index():
    response = make_response()
    response.status_code = 401
    response.headers = {'WWW-Authenticate': 'Basic realm="test"'} # Fail
    # response.headers = {b'WWW-Authenticate': b'Basic realm="test"'} # Succeed
    return response

if __name__ == '__main__':
    app.run(debug=True)

The app is available directly for debug purpose or through Nginx -> uWSGI -> Flask and works well.

  • When I use a browser to connect directly to the app, I've got a login dialog and the WWW-Authenticate header is correct.
  • The same request going through Nginx returns a header Transfert-Encoding: chunked and discard the WWW-Authenticate header.

Forcing bytestring ( b'...') format to add the header make the app works as expected in both cases. The file is encoded in UTF-8 and there's a b'...') format to add the header make the app works as expected in both cases. The file is encoded in UTF-8 and there's a coding` declaration for the Python interpreter. We're using Python 2.7.3, Nginx 1.4.2 and uWSGI 1.3.

Is there any known incompatibility between Nginx or uWSGI, Flask and unicode_literals? Thanks!

edit: The problem seems to come from uWSGI ( https://github.com/unbit/uwsgi/blob/master/plugins/python/wsgi_headers.c#L116 ), since it only checks for PyString and not PyUnicode for Python2, if I understand this code correctly.

edit: Armin Ronacher has fixed a similar bug ( https://github.com/mitsuhiko/flask/issues/758 ) 5 months ago, but I didn't find the commit in werkzeug git log yet. I don't know if the fix is scoped to the redirect() function or more broadly on headers handling. I'm using Werkzeug 0.9.4 and Flask 0.10.1.

This problem is indeed due to a bug in Werkzeug . As you noticed, this is now corrected since Jun 4, 2013 (cf. the related commit on Github). You can have a bug free version of Werkzeug by using the version 0.9.5 instead of the 0.9.4 .

Moreover, to troubleshoot your problem, I added app.debug = True just after the initialization of your Flask application. This allows me to got the following error in uWSGI logs:

Traceback (most recent call last):
  File "/home/afigura/.virtualenvs/stack-python2/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/afigura/.virtualenvs/stack-python2/lib/python2.7/site-packages/flask/app.py", line 1821, in wsgi_app
    return response(environ, start_response)
  File "/home/afigura/.virtualenvs/stack-python2/lib/python2.7/site-packages/werkzeug/wrappers.py", line 1201, in __call__
    start_response(status, headers)
TypeError: http header key must be a string

This corresponds to the error mentioned in the bug you found on Github.

So, you can use the following workaround to get Flask/Werkzeug working with unicode_literals :

response.headers = {b'WWW-Authenticate': 'Basic realm="test"'}

Or:

response.headers = {str('WWW-Authenticate'): 'Basic realm="test"'}

But I recommend to simply update your Werkzeug version to >=0.9.5 if you can.

Also, please note that although the headers attribute of a Flask/Werkzeug response behaves like a dictionary, it is in fact a Headers object (see Werkzeug source code ). Hence, I advise you to use it as follows:

response.headers['WWW-Authenticate'] = 'Basic realm="test"'

You can see some examples about this on the Flask documentation of the function make_response .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM