WSGI内容编码
如果我运行下面这个Python 3.1的程序,在浏览器里看到的却是�,而不是正确的字符。这个文件本身是用UTF-8编码的,而且响应中也发送了相同的编码。
from wsgiref.simple_server import make_server
page = "<html><body>äöü€ßÄÖÜ</body></html>"
def application(environ, start_response):
start_response("200 Ok", [("Content-Type", "text/html; charset=UTF-8")])
return page
httpd = make_server('', 8000, application)
print("Serving on port 8000...")
httpd.serve_forever()
响应中“UTF-8”设置得很正确:
HTTP/1.0 200 Ok
Date: Mon, 09 Aug 2010 16:35:02 GMT
Server: WSGIServer/0.1 Python/3.1.1+
Content-Type: text/html; charset=UTF-8
这里到底出了什么问题呢?
2 个回答
这些字符不是 UTF-8
编码的,而是 latin-1
编码的。如果你把这些字符直接放到你的 Python 源代码里(其实不应该这样做),你需要在文件的顶部声明一下编码方式,添加以下这一行:
#-*- coding: latin-1 -*-
然后以 latin-1
的方式来处理:
start_response("200 Ok", [("Content-Type", "text/html; charset=latin-1")])
假设你是想用 UTF-8 来处理所有内容,你需要查一下这些字符的编码点。然后你可以这样做:
page = u"\x--\x--...\x--"
并将其作为 Unicode 来使用。
注意,你可以通过改变浏览器的编码来验证这一点;如果你手动把编码改成 latin-1
,这些字符就能正常显示了。
在Python 3上,WSGI还没有正式推出。Web-SIG小组还没有就如何处理字符串(字节/Unicode)在Python 3.x中达成一致。
wsgiref
基本上是一个自动转换工具,把Python 2的代码转成Python 3的代码;但它仍然存在一些问题,尤其是关于WSGI在3.x中到底意味着什么。所以,不要把它当作Python 3下WSGI应用的参考。
在3.2版本发布周期中,情况依然如此,真让人感到尴尬和沮丧。
return page
虽然WSGI在3.x中的情况仍然不明朗,但大多数人都同意,WSGI应用的响应内容应该主要是字节,而不是Unicode,因为HTTP是基于字节的协议。至于Unicode字符串是否会被接受,以及如果接受的话会用什么编码转换,仍然有待观察,所以最好避免这个问题,直接返回字节:
return [page.encode('utf-8')]
([]
是必须的,因为WSGI应用应该返回一个可迭代的对象,每次输出和刷新一个项目。如果你单独传递一个字符串,它会被当作可迭代对象处理,一次返回一个字符,这样会严重影响性能。)