为什么 Twisted 认为我调用了 request.finish() 两次,而实际上我没有调用?
这是我在使用 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()
不是中的最后一行一个函数,然后我在它之后立即返回。
无论如何,我将此类添加到 /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()
我就无法重定向)。
This is an annoying problem I am having with Twisted.web. Basically, I have a class that inherits from twisted.web.resource.Resource
and adds some default stuff to Mako templates:
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 ""
Then, and I have narrowed the problem down to this small class (which I tested), I write a resource which inherits from 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()
I'd like to note that, in every other case, if request.finish()
isn't the last line in a function, then I return
immediately after it.
Anyways, I add this class to the site at /test
and when I navigate there, I get a submit button. I click the submit button, and in the console I get:
C:\Python26\lib\site-packages\twisted\web\server.py:200: UserWarning: Warning! request.finish called twice. self.finish()
But, I get this ONLY the first time I submit the page. Every other time, it's fine. I would just ignore this, but it's been nagging at me, and I can't for the life of me figure out why it's doing this at all, and why only the first time the page is submitted. I can't seem to find anything online, and even dropping print statements and tracebacks in the request.finish()
code didn't reveal anything.
edit
This morning I tried adding a second request.finish()
line to the resource, and it still only gave me the error one time. I suppose it will only warn about it in a resource once -- maybe per run of the program, or per session, I'm not sure. In any case, I changed it to:
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()
and just got two messages, one time. I still have no idea why I can't redirect the request without it saying I finished it twice (because I can't redirect without request.finish()
).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
简短回答
必须是:
详细回答
我决定筛选一些 Twisted 源代码。我首先添加了一个回溯到如果
request.finish()
被调用两次则打印错误的区域:我进入并在
twisted.web 中签出了
并发现:render
.serverbody
是渲染资源的结果,因此一旦填充body
,在我的问题中给出的示例情况中,finish
已在此请求对象上调用(因为self
从此方法传递到资源的 render 方法)。通过查看这段代码,很明显,通过返回
NOT_DONE_YET
我可以避免警告。我也可以将该方法的最后一行更改为:
但是,为了不修改库,简短的答案是:
在调用
request.redirect()
之后,您必须调用request .finish()
然后返回twisted.web.server.NOT_DONE_YET
更多
我发现了一些有关此内容的文档。它与重定向请求无关,而是使用
request.write()
渲染资源。它表示调用request.finish()
然后返回NOT_DONE_YET
。通过查看 render() 中的代码,我可以明白为什么会出现这种情况。Short Answer
It has to be:
Long Answer
I decided to go sifting through some Twisted source code. I first added a traceback to the area that prints the error if
request.finish()
is called twice:I went in and checked out
render
intwisted.web.server
and found this:body
is the result of rendering a resource, so oncebody
is populated, in the example case given in my question,finish
has already been called on this request object (sinceself
is passed from this method to the resource's render method).From looking at this code it becomes apparent that by returning
NOT_DONE_YET
I would avoid the warning.I could have also changed the last line of that method to:
but, in the interest of not modifying the library, the short answer is:
after calling
request.redirect()
you must callrequest.finish()
and thenreturn twisted.web.server.NOT_DONE_YET
More
I found some documentation about this. It isn't related to redirecting a request, but instead rendering a resource, using
request.write()
. It says to callrequest.finish()
and then returnNOT_DONE_YET
. From looking at the code inrender()
I can see why that is the case.