类型错误:期望字节串序列,但发现的值为字符串类型。

16

我正在尝试使用mod_wsgi运行Python 3的简单“hello world”应用程序。我正在使用Fedora 23。这是我的Apache虚拟主机配置:

<VirtualHost *:80>
    ServerName localhost
    ServerAdmin admin@localhost
    # ServerAlias foo.localhost
    WSGIScriptAlias /headers /home/httpd/localhost/python/headers/wsgi.py
    DocumentRoot /home/httpd/localhost/public_html
    ErrorLog /home/httpd/localhost/error.log
    CustomLog /home/httpd/localhost/requests.log combined
</VirtualHost>

wsgi.py:

def application(environ, start_response):
    status = '200 OK'
    output = 'Hello World!'

    response_headers = [('Content-Type', 'text/plain'),
                        ('Content-Length', str(len(output)))]

    start_response(status, response_headers)

    return [output]

如果我使用mod_wsgi来运行Python 2,就可以正常工作(sudo dnf remove python3-mod_wsgi -y && sudo dnf install mod_wsgi -y && sudo apachectl restart),但是使用Python 3时会收到500个内部服务器错误。以下是错误日志:

mod_wsgi (pid=899): Exception occurred processing WSGI script '/home/httpd/localhost/python/headers/wsgi.py'.
TypeError: sequence of byte string values expected, value of type str found

更新

str(len(output)) 上使用 encode() (或 encode('utf-8'))也不起作用。现在我得到的是:

Traceback (most recent call last):
  File "/home/httpd/localhost/python/headers/wsgi.py", line 8, in application
    start_response(status, response_headers)
TypeError: expected unicode object, value of type bytes found

1
你尝试过对字符串进行编码吗?例如:status.encode() - Rolbrok
在Python 3下,WSGI应用程序必须返回一个字节字符串作为变量'output'。它不能是Unicode对象或其他类型。(http://stackoverflow.com/questions/31918319/python-3-4-mod-wsgi-get-syntaxerror-invalid-syntax-r#comment51750828_31918319) <-- 我没有尝试,在一段时间内没有使用过Apache中的mod_wsgi - Remi Guan
status.encode('utf-8') ? - Rolbrok
这份文档似乎对这个主题不是很清楚... - Sumit
@Rolbrok:我尝试了,仍然出现“期望unicode,得到bytes”的错误。我已经使用LAMP配置相当长一段时间了,我想尝试在Apache下使用Python(带或不带Django)。我选择mod_wsgi而不是mod_python或cgi,因为它可以与Django开箱即用。 :) - Sumit
显示剩余8条评论
2个回答

38

显然变量output本身需要是字节字符串而不是Unicode字符串。 不仅对于response_headers,而且对于 output 使用的每个地方都需要更改(因此在第6行上使用str(len(output)).encode('utf-8')不起作用,就像我一直在尝试的那样)。

所以在我的情况下解决方案是:

def application(environ, start_response):
    status = '200 OK'
    output = b'Hello World!'

    response_headers = [('Content-type', 'text/plain'),
                        ('Content-Length', str(len(output)))]
    start_response(status, response_headers)

    return [output]

(此代码片段是Rolbrok在评论中建议的官方mod_wsgi仓库的一个测试


今晚这个问题让我头发都快白了!在凌晨4点之前,我偶然找到了解决方案。现在距离上班还有大约3个小时。只是想知道为什么需要这样做,是否有进一步的阅读材料? - Clint Street
为什么呢?这会让事情变得不必要的复杂。 - Soren

16

背景

这个问题是由于Python 3默认了UTF-8而引起的,因为今天我们发现有很多非母语英语字符,最好要容纳它们。HTTP仅使用ASCII字符工作,不能很好地处理UTF-8。因此,Apache和mod_wsgi都不能很好地处理UTF 8。

解决方案

因此,在准备整个HTML字符串之后,可以使用内置的Python函数 - bytes()进行类型转换。这需要一个字符串并给出一个字节串。

示例代码

html = "This "
html += "is the code"
html = bytes(html, encoding= 'utf-8')
response_header = [('Content-type', 'text/html')]
start_response(status, response_header)
yield html

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接