5

在 Nginx、uWSGI 和一个简单的 Flask 应用程序中添加启用 unicode_literals 的标头似乎会失败:

# -*- 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 -> Flask 并且运行良好。

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

强制字节串(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 aPython 解释器的编码声明。我们使用 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。

4

1 回答 1

1

这个问题确实是由于Werkzeug中的一个错误造成的。正如您所注意到的,自 2013 年 6 月 4 日起,这一问题现已得到纠正(参见 Github 上的相关提交)。您可以使用版本0.9.5而不是0.9.4来获得 Werkzeug 的无错误版本。

此外,为了解决您的问题,我app.debug = True在您的 Flask 应用程序初始化之后添加。这允许我在 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 上发现的错误中提到的错误。

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

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

或者:

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

但如果可以的话,我建议将您的 Werkzeug 版本简单地更新为 >=0.9.5。

另外,请注意,虽然headersFlask/Werkzeug 响应的属性表现得像字典,但它实际上是一个Headers对象(参见Werkzeug 源代码)。因此,我建议您按以下方式使用它:

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

您可以在函数的Flask 文档中看到一些关于此的示例make_response

于 2015-03-30T09:22:00.943 回答