使用unicode_literals在Flask应用中添加标头

时间:2013-10-16 18:05:06

标签: python unicode nginx flask

使用unicode_literals启用添加标头似乎失败了Nginx,uWSGI和一个简单的Flask应用程序:

# -*- 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)

该应用程序可直接用于调试目的或通过Nginx - > uWSGI - >烧瓶并且效果很好。

  • 当我使用浏览器直接连接到应用程序时,我有一个登录对话框和 WWW-Authenticate标题是正确的。
  • 通过Nginx的同一请求会返回标头Transfert-Encoding: chunked和 丢弃WWW-Authenticate标题。

强制Python解释器的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 coding`声明。 我们使用的是Python 2.7.3,Nginx 1.4.2和uWSGI 1.3。

Nginx或uWSGI,Flask和unicode_literals之间是否存在任何已知的不兼容性? 谢谢!

编辑: 问题似乎来自uWSGI( https://github.com/unbit/uwsgi/blob/master/plugins/python/wsgi_headers.c#L116),因为它只检查PyString而不检查Python2的PyUnicode,如果我正确理解这段代码的话。

编辑: Armin Ronacher在5个月前修复了类似的错误(https://github.com/mitsuhiko/flask/issues/758),但我还没有在werkzeug git log中找到提交。我不知道修复是否作用于redirect()函数或更广泛地处理头文件。我正在使用Werkzeug 0.9.4和Flask 0.10.1。

1 个答案:

答案 0 :(得分:1)

此问题确实是由于 Werkzeug 中的错误造成的。正如您所注意到的,现在自2013年6月4日起更正(参见Github上的related commit)。您可以使用版本 0.9.5 而不是 0.9.4 来获得Werkzeug的无错版本。

此外,为了解决您的问题,我在Flask应用程序初始化后添加了app.debug = True。这允许我在uWSGI日志中出现以下错误:

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

这对应于Github上the bug you found中提到的错误。

因此,您可以使用以下解决方法让 Flask / Werkzeug unicode_literals一起使用:

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

或者:

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

但我建议您只需将Werkzeug版本更新为> = 0.9.5即可。

另外,请注意,虽然Flask / Werkzeug响应的headers属性的行为类似于字典,但它实际上是Headers对象(请参阅Werkzeug source code)。因此,我建议你按如下方式使用它:

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

您可以在函数make_response的{​​{3}}上看到有关此问题的一些示例。