代码之家  ›  专栏  ›  技术社区  ›  Carson Myers

为什么Twisted认为我在调用request.finish()两次而我没有?

  •  10
  • Carson Myers  · 技术社区  · 14 年前

    这是我在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()
    

    ).

    1 回复  |  直到 14 年前
        1
  •  11
  •   Carson Myers    8 年前

    简短的回答


    request.redirect("/test")
    request.finish()
    return twisted.web.server.NOT_DONE_YET
    

    冗长的回答


    我决定去筛选一些扭曲的源代码。我首先在打印错误的区域添加了一个回溯,如果 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 是呈现资源的结果,所以 身体 在我的问题中给出的例子中, finish 已对此请求对象调用(自 self 从该方法传递到资源的呈现方法)。

    通过查看此代码,很明显 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() . 从查看 render() 我明白为什么会这样。