这是我在使用Twisted.web时遇到的烦人问题。基本上,我有一个继承自twisted.web.resource.Resource
的类,并为Mako模板添加了一些默认内容:
from twisted.web.resource import Resource
from mako.lookup import TemplateLookup
from project.session import SessionData
from project.security import make_nonce
class Page(Resource):
template = ""
def display(self, request, **kwargs):
session = SessionData(request.getSession())
if self.template:
templates = TemplateLookup(directories=['templates'])
template = templates.get_template(self.template)
return template.render(user=session.user,
info=session.info,
current_path=request.path,
nonce=make_nonce(session),
**kwargs)
else:
return ""
然后,我已将问题缩小到这个小类(我测试过),我写了一个继承自Page
的资源:
class Test(pages.Page):
def render_GET(self, request):
return "<form method='post'><input type='submit'></form>"
def render_POST(self, request):
request.redirect("/test")
request.finish()
我想要注意的是,在其他所有情况下,如果request.finish()
不是函数的最后一行,那么我return
就在它之后。
无论如何,我将此课程添加到/test
的网站,当我在那里导航时,我会收到一个提交按钮。我点击提交按钮,在控制台中我得到:
C:\Python26\lib\site-packages\twisted\web\server.py:200: UserWarning: Warning! request.finish called twice. self.finish()
但是,我第一次提交页面时才会收到此信息。每隔一段时间,这很好。我会忽略这一点,但它一直在唠叨我,我不能为我的生活找出它为什么这样做,以及为什么只有第一次提交页面。我似乎无法在网上找到任何东西,甚至在request.finish()
代码中删除了打印语句和回溯也没有透露任何内容。
今天早上我尝试在资源中添加第二条request.finish()
行,但它仍然只给了我一次错误。我想它只会在一次资源中警告它 - 也许每次运行程序,或者每次会话,我不确定。无论如何,我把它改为:
class Test(pages.Page):
def render_GET(self, request):
return "<form method='post'><input type='submit'></form>"
def render_POST(self, request):
request.redirect("/test")
request.finish()
request.finish()
只有两条消息,一次。我仍然不知道为什么我不能重新定向请求而没有说我完成了两次(因为我不能在没有request.finish()
的情况下重定向)。
答案 0 :(得分:10)
必须是:
request.redirect("/test")
request.finish()
return twisted.web.server.NOT_DONE_YET
我决定对一些Twisted源代码进行筛选。我首先在该区域添加了一个回溯,如果request.finish()
被调用两次,则会打印错误:
def finish(self):
import traceback #here
"""
Indicate that all response data has been written to this L{Request}.
"""
if self._disconnected:
raise RuntimeError(
"Request.finish called on a request after its connection was lost; "
"use Request.notifyFinish to keep track of this.")
if self.finished:
warnings.warn("Warning! request.finish called twice.", stacklevel=2)
traceback.print_stack() #here
return
#....
... File "C:\Python26\lib\site-packages\twisted\web\server.py", line 200, in render self.finish() File "C:\Python26\lib\site-packages\twisted\web\http.py", line 904, in finish traceback.print_stack()
我进去并在render
中查看twisted.web.server
并找到了:
if body == NOT_DONE_YET:
return
if type(body) is not types.StringType:
body = resource.ErrorPage(
http.INTERNAL_SERVER_ERROR,
"Request did not return a string",
"Request: " + html.PRE(reflect.safe_repr(self)) + "<br />" +
"Resource: " + html.PRE(reflect.safe_repr(resrc)) + "<br />" +
"Value: " + html.PRE(reflect.safe_repr(body))).render(self)
if self.method == "HEAD":
if len(body) > 0:
# This is a Bad Thing (RFC 2616, 9.4)
log.msg("Warning: HEAD request %s for resource %s is"
" returning a message body."
" I think I'll eat it."
% (self, resrc))
self.setHeader('content-length', str(len(body)))
self.write('')
else:
self.setHeader('content-length', str(len(body)))
self.write(body)
self.finish()
body
是渲染资源的结果,因此填充body
后,在我的问题中给出的示例案例中,finish
已在此请求对象上调用(从self
从此方法传递到资源的render方法。
通过查看此代码,很明显,通过返回NOT_DONE_YET
,我会避免警告。
我本可以将该方法的最后一行更改为:
if not self.finished:
self.finish()
但是,为了不修改库,简短的回答是:
致电request.redirect()
后,您必须致电request.finish()
,然后致电return twisted.web.server.NOT_DONE_YET
我发现了一些documentation。它与重定向请求无关,而是使用request.write()
呈现资源。它说要拨打request.finish()
然后返回NOT_DONE_YET
。通过查看render()
中的代码,我可以看出为什么会出现这种情况。