Twisted无缘无故抛出“只能在Python 2上传递字节”错误

0 投票
2 回答
676 浏览
提问于 2025-04-18 23:06

我正在用 twisted 作为我的网页服务器,利用这个设置来提供普通的文本网站和二进制文件下载。

我在六台机器上使用完全相同的设置,唯一的区别是三台运行 Debian,另外三台运行 Ubuntu。

在我的三台 Ubuntu 机器中,有两台出现了这个错误:

Unhandled Error
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/twisted/protocols/basic.py", line 571, in dataReceived
    why = self.lineReceived(line)
  File "/usr/lib/python2.7/dist-packages/twisted/web/http.py", line 1655, in lineReceived
    self.allContentReceived()
  File "/usr/lib/python2.7/dist-packages/twisted/web/http.py", line 1730, in allContentReceived
    req.requestReceived(command, path, version)
  File "/usr/lib/python2.7/dist-packages/twisted/web/http.py", line 826, in requestReceived
    self.process()
--- <exception caught here> ---  
  File "/usr/lib/python2.7/dist-packages/twisted/web/server.py", line 189, in process
    self.render(resrc)
  File "/usr/lib/python2.7/dist-packages/twisted/web/server.py", line 238, in render
    body = resrc.render(self)
  File "/usr/lib/python2.7/dist-packages/twisted/web/resource.py", line 250, in render
    return m(request)
  File "/usr/lib/python2.7/dist-packages/twisted/web/static.py", line 631, in render_GET
    producer.start()
  File "/usr/lib/python2.7/dist-packages/twisted/web/static.py", line 710, in start
    self.request.registerProducer(self, False)
  File "/usr/lib/python2.7/dist-packages/twisted/web/http.py", line 872, in registerProducer
    self.transport.registerProducer(producer, streaming)
  File "/usr/lib/python2.7/dist-packages/twisted/internet/_newtls.py", line 233, in registerProducer
    FileDescriptor.registerProducer(self, producer, streaming)
  File "/usr/lib/python2.7/dist-packages/twisted/internet/abstract.py", line 112, in registerProducer
    producer.resumeProducing()
  File "/usr/lib/python2.7/dist-packages/twisted/web/static.py", line 720, in resumeProducing
    self.request.write(data)
  File "/usr/lib/python2.7/dist-packages/twisted/web/server.py", line 217, in write
    http.Request.write(self, data)
  File "/usr/lib/python2.7/dist-packages/twisted/web/http.py", line 1001, in write
    value = networkString('%s' % (value,))
  File "/usr/lib/python2.7/dist-packages/twisted/python/compat.py", line 364, in networkString
    raise TypeError("Can only pass-through bytes on Python 2")
exceptions.TypeError: Can only pass-through bytes on Python 2
Unhandled Error
Traceback (most recent call last):
Failure: exceptions.RuntimeError: Producer was not unregistered for /file/10983801

而另一台则运行得很好。

所有三台 Ubuntu 服务器上的 Python 版本都是:ii python2.7 2.7.6-8 amd64

我最近没有更新 Python,也没有对我的代码做任何更改。我还尝试重启机器,但没有成功。

我非常希望能得到一些提示。 在谷歌搜索时只找到了这个链接: 在 Windows 上运行 Portia (scrapy) 但由于我使用的是 2.7.6 和 Linux,这个情况应该不适用。

编辑:附上实际的代码:

class PyQueueFile(Resource):

    def __init__(self):
        Resource.__init__(self)
        self.ipcTalker = talker.Talker()

    def getChild(self, convert_id, request):
        """
        :param request: The http Request
        :type request: twisted.web.http.Request
        """
        try:
            db = database.Database()
            video = db.getVideo(convert_id)

            request.setHeader("Content-Disposition",
                              "attachment; filename=\"" + os.path.basename(video['title'] + "." + video['format']) + "\"")
            request.setHeader("Content-type", "application/force-download")

            fileResponse = File(video['path'])
        except TypeError:
            return Page404()

        return fileResponse


def fireup():
    try:

        myconfig = config.Config()

        root = Resource()
        root.putChild("file", PyQueueFile())

        factory = Site(root)
        reactor.listenTCP(myconfig.webPort, factory, 100, myconfig.webIp)
        reactor.run()
    except (KeyboardInterrupt, SystemExit):
        reactor.stopListening()

编辑 2: 我也尝试通过 pip 安装 twisted,结果还是同样的问题。 :/

2 个回答

1

在邮件列表的帮助下,我解决了这个问题。

问题是由一个unicode字符串引起的。

把这一行:

"attachment; filename=\"" + os.path.basename(video['title'] + "." + video['format']) + "\"")

改成这样:

"attachment; filename=\"" + str(os.path.basename(video['title']) + "." + video['format']) + "\"")

就解决了这个问题。不过我还是不明白为什么在所有平台上都没有出现这个问题?

3

查看一下在https://docs.python.org/2/howto/unicode.html中关于“unicode文件名”的章节,这里有解释:

>>> import os
>>> os.path.basename(u'/a/b/c')
u'c'
>>> os.path.basename('/a/b/c')
'c'

不过,你的修复方法在文件名中遇到非ASCII字符时会失败,应该使用URL编码(urllib.urlencode)。

撰写回答