HTTP redirection from data_*/render_* methods
I wondered if I can make an HTTP redirection (302) from inside of render_* or data_* method. Here is a code snipped I wrote; I'd like to know if it can be considered as "good" nevow practice? from nevow import rend, loaders, inevow from twisted.internet import defer class MyPage(rend.Page): addSlash = True docFactory = loaders.xmlstr("""\ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en" xmlns:nevow="http://nevow.com/ns/nevow/0.1"> <body> <div nevow:render="redirect http://google.com">Nothing is here</div> </body> </html> """) buffered = True def renderHTTP(self, ctx): """The renderHTTP method is overloaded to add errback handler to the rendering Deferred object""" d = defer.maybeDeferred(rend.Page.renderHTTP, self, ctx) d.addErrback(self.onError, ctx) return d # # Custom exception-based class to request redirection # class __Redirect(Exception): pass def onError(self, failure, ctx): if isinstance(failure.value, self.__Redirect): # # If a redirection was requested, then drop the output buffer # and redirect the Request object # inevow.IRequest(ctx).redirect(failure.value.args[0]) return "" # # Otherwise, fall through # return failure # # Convenience method to be called from inside of render_* or data_* # callback # def __redirect(self, url): raise self.__Redirect, url # # # def render_redirect(self, url): return lambda ctx, data: self.__redirect(url) The "redirect" render directive could be used depending on some another logic in the page, if some pattern was assigned to the containing tag. Any comments will be very appreciated. -- jk
At 2005-07-15 02:46 PM +0400, you wrote:
I wondered if I can make an HTTP redirection (302) from inside of render_* or data_* method. Here is a code snipped I wrote; I'd like to know if it can be considered as "good" nevow practice?
What about request.redirect( redirectUrl ) possibly followed by request.finish() I haven't ported my app to the latest nevow version (still on v. 0.1d), but redirects are sufficiently useful and common that I would expect request.redirect to still work. - Sam __________________________________________________________ Spinward Stars, LLC Samuel Reynolds Software Consulting and Development 303-805-1446 http://SpinwardStars.com/ sam@SpinwardStars.com
On Fri, Jul 15, 2005 at 07:40:33AM -0600, Samuel Reynolds wrote:
At 2005-07-15 02:46 PM +0400, you wrote:
I wondered if I can make an HTTP redirection (302) from inside of render_* or data_* method. Here is a code snipped I wrote; I'd like to know if it can be considered as "good" nevow practice?
What about request.redirect( redirectUrl ) possibly followed by request.finish()
It doesn't work when called from inside a render_something or data_smth methods. If I redirect, I want the flattening process to stop immediately, dropping request output accumulated so far. The only way to do it is to raise an exception, cancelling normal flow. Otherwise, flattening will continue, and the request will be finished twice. Also, the http reply will have non-empty body. -- jk
On Jul 15, 2005, at 7:17 AM, <en.karpachov@ospaz.ru> <en.karpachov@ospaz.ru> wrote:
On Fri, Jul 15, 2005 at 07:40:33AM -0600, Samuel Reynolds wrote:
At 2005-07-15 02:46 PM +0400, you wrote:
I wondered if I can make an HTTP redirection (302) from inside of render_* or data_* method. Here is a code snipped I wrote; I'd like to know if it can be considered as "good" nevow practice?
What about request.redirect( redirectUrl ) possibly followed by request.finish()
It doesn't work when called from inside a render_something or data_smth methods. If I redirect, I want the flattening process to stop immediately, dropping request output accumulated so far. The only way to do it is to raise an exception, cancelling normal flow. Otherwise, flattening will continue, and the request will be finished twice. Also, the http reply will have non-empty body.
Even if you do raise an exception, all output generated up to that point will have already been sent out over the socket to the browser. This means the headers will already have been written, and redirecting will have no effect. What you want instead is to set the "buffered" attribute of your Page class to true before it starts rendering. This will cause nevow to delay sending any output to the browser until the entire page is done rendering, allowing you to do a redirect in the middle of it. Personally, I don't think it's a good idea. You should decide about the redirect up front, that way you avoid doing wasted work on the server. Buffering also isn't as cool, because pages will chunk in rather than streaming in. Donovan
On Fri, Jul 15, 2005 at 11:45:24AM -0700, Donovan Preston wrote:
Even if you do raise an exception, all output generated up to that point will have already been sent out over the socket to the browser. This means the headers will already have been written, and redirecting will have no effect.
It is why I set the buffered = True in my example.
What you want instead is to set the "buffered" attribute of your Page class to true before it starts rendering. This will cause nevow to delay sending any output to the browser until the entire page is done rendering, allowing you to do a redirect in the middle of it.
Personally, I don't think it's a good idea. You should decide about the redirect up front, that way you avoid doing wasted work on the
Well, one possible usage example could be <table nevow:data="sqlquery" nevow:render="sequence"> <tr nevow:pattern="item"><td>...</td></tr> <tr nevow:pattern="empty"> <td nevow:render="redirect /notfound">None at all</td> </tr> </table>
server. Buffering also isn't as cool, because pages will chunk in rather than streaming in.
Donovan
Thanks! -- jk
On Fri, Jul 15, 2005 at 07:40:33AM -0600, Samuel Reynolds wrote:
At 2005-07-15 02:46 PM +0400, you wrote:
I wondered if I can make an HTTP redirection (302) from inside of render_* or data_* method. Here is a code snipped I wrote; I'd like to know if it can be considered as "good" nevow practice?
What about request.redirect( redirectUrl ) possibly followed by request.finish()
That is, this method doesn't allow to return an empty body. If it is ok to return fully rendered page together with the "302 Found", then it is probably enough to call request.redirect, that's right. So the render method from my snippet should probably look like def render_redirect(self, url): def _(ctx, data): inevow.IRequest.redirect(str(url)) return "Redirecting" return _ Thanks for your hint. -- jk
participants (4)
-
Donovan Preston
-
en.karpachov@ospaz.ru
-
Samuel Reynolds
-
Tommi Virtanen