See stackoverflow:
So I tried something like this:
// Catch 404s
LiftRules.uriNotFound.prepend {
case (req, _) => RewriteResponse("404" :: Nil)
}
But of course RewriteResponse is not a LiftResponse. Whats the best
way to do this? Basically I've got a template called 404.html which
I'd like to display whenever there is a 404.
I Just thought of something, perhaps I could add a RewriteRule that
matches everything?
- Alex
If you want to display the contents of your 404.html, checkout NodeResponse... just load up your template using the template helpers (this will give you NodeSeq) and then you can present that back to the user. Job done.
Cheers, Tim
I had tried it, and got a compile error, keep in mind I'm still on
1.0:
http://scala-tools.org/scaladocs/liftweb/1.0/net/liftweb/http/RewriteResponse.html
> If you want to display the contents of your 404.html, checkout NodeResponse... just load up your template using the template helpers (this will give you NodeSeq) and then you can present that back to the user. Job done.
I'll take a look, that sounds promising, thx. What are the template
helpers? This sounds similar to using S.render, but I wasn't able to
use that since I'm still on 1.0, it looks like it was added later. (I
am considering moving to 1.1-M6).
- Alex
-Ross
> --
>
> You received this message because you are subscribed to the Google
> Groups "Lift" group.
> To post to this group, send email to lif...@googlegroups.com.
> To unsubscribe from this group, send email to liftweb+u...@googlegroups.com
> .
> For more options, visit this group at http://groups.google.com/group/liftweb?hl=en
> .
>
>
I am familiar with NodeResponse and its subclasses. I've used them in
our REST api. But, what I can't figure out, is how to use them in
conjuction with the templating engine as you seem to be alluding to
(with the template helpers).
Can you point me in the right direction? I am going to try switching
to M8 and then using S.render like this:
val node404 = <lift:surround with="default" at="content">
<h1>Not Found</h1>
</lift:surround>
LiftRules.uriNotFound.prepend {
case (req, _) => XhtmlResponse(S.render(node404, req), _,
headers, cookies, 404, false)
Cheers, Indrajit
>> <mailto:lif...@googlegroups.com>.
>> > To unsubscribe from this group, send email to
>> liftweb+u...@googlegroups.com
>> <mailto:liftweb%2Bunsu...@googlegroups.com>
>> > .
>> > For more options, visit this group at
>> http://groups.google.com/group/liftweb?hl=en
>> > .
>> >
>> >
>>
>> --
>>
>> You received this message because you are subscribed to the Google
>> Groups "Lift" group.
>> To post to this group, send email to lif...@googlegroups.com
>> <mailto:lif...@googlegroups.com>.
>> To unsubscribe from this group, send email to
>> liftweb+u...@googlegroups.com
>> <mailto:liftweb%2Bunsu...@googlegroups.com>.
>> For more options, visit this group at
>> http://groups.google.com/group/liftweb?hl=en.
>>
>>
>>
>>
>>
>> --
>> http://blog.alexblack.ca <http://blog.alexblack.ca/>
>> http://twitter.com/waterlooalex
>>
>> --
>>
>> You received this message because you are subscribed to the Google
>> Groups "Lift" group.
>> To post to this group, send email to lif...@googlegroups.com
>> <mailto:lif...@googlegroups.com>.
>> To unsubscribe from this group, send email to
>> liftweb+u...@googlegroups.com
>> <mailto:liftweb+u...@googlegroups.com>.
// A node which embeds our 404 template (e.g. 404.html)
val notFoundNode =
<lift:embed what="404" />
// Catch 404s
LiftRules.uriNotFound.prepend {
case (req, _) => XhtmlTemplateResponse(notFoundNode, 404)
}
// If you're using a sitemap, make sure you have a catch-all item,
e.g
// Menu(Loc("Catchall", Pair(Nil, true), "", Hidden :: Nil)) ::
using this object:
object XhtmlTemplateResponse extends HeaderStuff {
def apply(nodeToRender: Node, statusCode: Int): LiftResponse = {
val renderedNode = S.render(nodeToRender,
S.request.get.request).first
new XhtmlResponse(renderedNode, Empty, headers, cookies,
statusCode, false)
}
}
I think the wiki page: http://wiki.liftweb.net/index.php/Setting_up_a_custom_404_page
should be updated. The current code hides the 404 status code and
changes the url.
I'd offer to write the new wiki page - is there a way for me to get an
account on that wiki - or is it just for contributors?
- Alex
M8 is pretty stable, yes. M7 was not, and so M6 was recommended before that. I haven't heard of any reason to recommend M6 over M8, but maybe dpp has some reasons.
--
You received this message because you are subscribed to the Google Groups "Lift" group.
To post to this group, send email to lif...@googlegroups.com.
To unsubscribe from this group, send email to liftweb+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/liftweb?hl=en.
I tried your suggestion, and it works well except I'm encountering one
issue, my sitemap renders as "No Navigation Defined." for urls that
are not found. I'm using 1.1-M8, I launched jetty in production mode
as you indicated, and added the passNotFoundToChain = false.
Did you expect that - or is the passNotFoundToChain meant to solve the
sitemap issue?
- Alex
On Dec 29, 6:10 pm, David Pollak <feeder.of.the.be...@gmail.com>
wrote:
> > liftweb+u...@googlegroups.com<liftweb%2Bunsu...@googlegroups.com>
> > .
> > For more options, visit this group at
> >http://groups.google.com/group/liftweb?hl=en.
>
> --
> Lift, the simply functional web frameworkhttp://liftweb.net
> Beginning Scalahttp://www.apress.com/book/view/1430219890
-Ross
> To unsubscribe from this group, send email to liftweb+u...@googlegroups.com.
Here's what I'm seeing:
1. If I run with -Drun.mode=production, and I access a not found url,
say mysite.com/foobar, then, I *do* see the custom 404 page as
expected, but, where I normally see my sitemap I see "No Navigation
Defined".
2. If I run *without* that production flag, and I access a not found
url, I get a blank white screen that says "The requested page was not
defined in your SiteMap, so access was blocked. (This message is
displayed in development mode only)".
So #2 is expected, #1 is not.
Ross, when you emailed me you said you tried to reproduce this, but I
think one difference between your scenario and mine is that on my 404
page I have a sitemap rendered.
So instead of what dpp had:
LiftRules.uriNotFound.prepend {
case _ => XhtmlResponse((<html> <body>Silly goose</body> </
html>),
Empty, List("Content-Type" -> "text/
html;
charset=utf-8"), Nil, 404, S.ieMode)
}
I have:
// Catch 404s
LiftRules.uriNotFound.prepend {
case (req, _) => XhtmlTemplateResponse(notFoundNode, 404)
}
with
object XhtmlTemplateResponse extends HeaderStuff {
def apply(nodeToRender: Node, statusCode: Int): LiftResponse = {
val renderedNode = S.render(nodeToRender,
S.request.get.request).first
new XhtmlResponse(renderedNode, Empty, headers, cookies,
statusCode, false)
}
}
- Alex
notFoundNode is defined like this:
val notFoundNode = <lift:embed what="404" />
and 404.html like this:
<lift:surround with="default" at="content">
<head>
<title>Page Not Found</title>
</head>
<h1>Page Not Found</h1>
<p>We couldn't find the page you were looking for.</p>
</lift:surround>
And my default.html hidden template has a site map tag in it, and the
sitemap contains a number of entries.
I'm hoping you can suggest the right way, to create a custom 404 page,
correctly (without a redirect, with 404 status code), and processed by
the template engine so it uses our default template with sitemap etc.
- Alex
Here's a version that works:
In Boot:
val notFoundNode = <lift:embed what="404" />
LiftRules.uriNotFound.prepend {
case _ => XhtmlTemplateResponse(notFoundNode, 404)
}
And the other part:
object XhtmlTemplateResponse extends HeaderStuff {
def apply(nodeToRender: NodeSeq, statusCode: Int): LiftResponse = {
val renderedNode = {
val forceToRoot: LiftRules.RewritePF = { case _ => RewriteResponse(Req.parsePath("/"), TreeMap.empty, true) }
for (req <- S.request; session <- S.session) yield
S.init(Req(req, forceToRoot::Nil), session) {
session.processSurroundAndInclude("/", nodeToRender)
}
} openOr {
error("No session")
}
new XhtmlResponse(Group(renderedNode), Empty, headers, cookies, statusCode, false)
}
}
The secret sauce is reiniting S with a new request that has been rewritten to seem as if it were a hit to /
I'm not sure if this is a good idea, but it seems to work for the site map thing.
However, I can't find a way to make the head merge work properly. It looks like the head merging lies in the code path inside LiftSession that is private to Lift. You could rearrange your template to make only one head I guess, or wait until someone more wise than I can direct you as far as that goes.
-Ross
I would advice no doing such things or if you do, then expect side
effects. In general avoid bypassing Lift's rendering pipeline. Lift
does a lot of things some of them internal and missing those you can
get into nasty hidden problems.
For head merge you could use HeadHelper.scala but note that internally
Lift doesn't use this ... it uses a more sophisticated head merge ...
see LiftMerge.scala. HeadHelper holds the old merge. IMO it should be
removed.
I'm not really sure why you guys don't like redirects, probably to
avoid traffic, but IMO this is not very relevant. But regardless, you
guys have your own reasons.
Br's,
Marius
> ...
>
> read more »
Stepping back a moment, conceptually what I'd like to do is: create a
nice 404.html template (using lift features like head merge and
surround tags and sitemap), and then tell Lift to show this page to my
users when it can't find a handler for the url requested.
Conceptually a nice solution might be:
LiftRules.uriNotFound.prepend {
case _ => RewriteResponse("404.html")
}
Any other opinions on Russ's solution? Is it the right way to go? Or
is there another way? Or perhaps could we propose an enhancement to
Lift to handle this well?
To Marius's question about why I (and perhaps others) don't want to
use a redirect:
It breaks the internet. The way its meant to work is: a user-agent
(either browser, or crawler etc) asks a web server for a resource by
url, the web server should respond with code 404 if it can't find the
resource. Your proposal would have it respond with code 301 which
tells the user-agent that the resource was located but its moved.
LIft is generally very good I've found at making it easy to build good
internet applications the *right* way. Examples include: its easy to
build rest-ful APIs and return the correct response codes, its easy to
re-write urls to have friendly urls for users, its easy to build XHTML
compliant pages etc.
This is one of those areas where we (the lift community) should make
sure that Lift makes it easy to do things the right way. Unlike say
Microsoft of the past where they continually broke internet standards
and made it easy to do things the wrong way!
- Alex
> ...
>
> read more »
http://googlewebmastercentral.blogspot.com/2008/08/farewell-to-soft-404s.html
> ...
>
> read more »
On Dec 30, 5:05 pm, Alex Black <a...@alexblack.ca> wrote:
> I'll try out that solution Russ, thanks. Although as the solution
> gets a bit more complex, and taking into account Marius's advice, it
> sounds like this might not be the right direction to go in.
>
> Stepping back a moment, conceptually what I'd like to do is: create a
> nice 404.html template (using lift features like head merge and
> surround tags and sitemap), and then tell Lift to show this page to my
> users when it can't find a handler for the url requested.
>
> Conceptually a nice solution might be:
>
> LiftRules.uriNotFound.prepend {
> case _ => RewriteResponse("404.html")
> }
>
> Any other opinions on Russ's solution? Is it the right way to go? Or
> is there another way? Or perhaps could we propose an enhancement to
> Lift to handle this well?
>
> To Marius's question about why I (and perhaps others) don't want to
> use a redirect:
>
> It breaks the internet. The way its meant to work is: a user-agent
> (either browser, or crawler etc) asks a web server for a resource by
> url, the web server should respond with code 404 if it can't find the
> resource. Your proposal would have it respond with code 301 which
> tells the user-agent that the resource was located but its moved.
While I totally agree that a plain 404 + markup is much more
straightforward,
"breaks internet" are too big words :) .. sending back a
302 or 301 tells the UA "you asked me for a resource that I know I
don't have but I wont tell
you explicitely, instead I want you to go to this location as an
alternative resource". Somehow it's like scratching with the wrong
hand and purely from HTTP protocol perspective this is not quite
straightforward as 404 + template, but I don't necessarily see it as a
so bad thing.
Specifically for 404 (when a template is not found we could do
something like:
1. In LiftRules instead of:
type URINotFoundPF = PartialFunction[(Req, Box[Failure]),
LiftResponse]
use
type URINotFoundPF = PartialFunction[(Req, Box[Failure]), Either[List
[String], LiftResponse]]
so that function can return a template path instead of response.
2. In LiftSession#processRequest instead of applying the normal
request pipeline only if the addressed template is found, we can use
the path obtained from LiftRules.uriNotFound if Lift fails to find the
normal tempalte. Hence apply the normal rendering pipeline to the
template referenced by uriNotFound.
This approach allows your 404 case to be handled by the normal
rendering pipeline without other hacks.
Unless someone thinks this is a bad solution, Alex you could open an
issue and I'll work on it.
Br's,
Marius
Br's,
Marius
> ...
>
> read more »
Also, it seems odd there's no way to invoke the normal template flow
even barring the re-init of S. The closest you can get that I know of
is LiftSession.processSurroundAndInclude or S.render, but neither of
those do head merge which seems to be a very key part of the rendering
pipeline. Perhaps I'm misreading the code? It looks like
LiftMerge.merge is called from LiftSession.processRequest which is
called from LiftServlet.dispatchStatefulRequest, and so on, all
private to net.liftweb.http.
At any rate, I'm just trying to help Alex, I'm not invested in any
reason other than it's informative to try and solve. Is there any way
to get a templated 404 response?
-Ross
>>> --
>>
>>> You received this message because you are subscribed to the Google
>>
>> ...
>>
>> read more »
>
> --
>
> You received this message because you are subscribed to the Google
> Groups "Lift" group.
> To post to this group, send email to lif...@googlegroups.com.
> To unsubscribe from this group, send email to liftweb+u...@googlegroups.com
Br's,
Marius
> ...
>
> read more »
Heh, I apologise, definitely "breaking the internet" is a bit
dramatic. I do have a different view than you though, I think its
incorrect to return a 301 or 302 in these scenarios, the correct
response is 404. Not only is it the correct response, but given most
sites get 50%-90% of their traffic from Google, and Google thinks its
also correct to return 404 (http://www.google.com/url?sa=D&q=http://
googlewebmastercentral.blogspot.com/2008/08/farewell-to-
soft-404s.html, its in our best financial interest to play nice with
Google.
> Specifically for 404 (when a template is not found we could do
> something like:
>
> 1. In LiftRules instead of:
>
> type URINotFoundPF = PartialFunction[(Req, Box[Failure]),
> LiftResponse]
>
> use
>
> type URINotFoundPF = PartialFunction[(Req, Box[Failure]), Either[List
> [String], LiftResponse]]
>
> so that function can return a template path instead of response.
>
> 2. In LiftSession#processRequest instead of applying the normal
> request pipeline only if the addressed template is found, we can use
> the path obtained from LiftRules.uriNotFound if Lift fails to find the
> normal tempalte. Hence apply the normal rendering pipeline to the
> template referenced by uriNotFound.
>
> This approach allows your 404 case to be handled by the normal
> rendering pipeline without other hacks.
>
> Unless someone thinks this is a bad solution, Alex you could open an
> issue and I'll work on it.
Thanks for proposing that solution Marius. I can't really comment on
whether or not its the right way to do it from Lift's point of view,
but as a user of Lift it sounds like it would work well.
- Alex
Sorry Ross, perhaps my response didn't convey my appreciation for your
help, or maybe it came off sounding negative, I didn't mean that.
What I meant was: thanks for offering that solution, it looks like a
step forward, I appreciate your help, but based on my gut feeling
looking at that code and based on Marius's opinon, I don't think we're
yet at an elegant robust solution, so lets keep coming up with more
ideas.
- Alex
> ...
>
> read more »
Other opinions on this?
Br's,
Marius
-Ross
I hope I wrote it in a reasonable/acceptable way, its my first ticket.
- Alex
On Dec 30, 11:26 am, Marius <marius.dan...@gmail.com> wrote:
> Please open a defect herehttp://github.com/dpp/liftweb/issues...
-------------------------------------
Marius<marius...@gmail.com> wrote:
Other opinions on this?
Br's,
Marius
--
1. Having a TemplateResponse holding a path without the rendering
logic, people could use that to send a response to the client, which
would be incorrect as having a LiftResponse holding /a/b/c doesn;t
mean anything to a client. And this would alter the semantics of a
LiftResponse. That's why I proposed an Either.
2. On the other hand if we have a TemplateResponse holding the logic
of processing a template (similar to the one proposed on this thread)
would mean that we're doing the processing outside of the normal
rendering pipeline which has the downsides discussed.
Br's,
Marius
On Dec 30, 8:18 pm, Naftoli Gugenheim <naftoli...@gmail.com> wrote:
> Would it not be possible to have a LiftResponse that runs through the regular plumbing? This way instead of introducing Either you can just use a TemplateResponse etc.
>
> -------------------------------------
>
Please open a defect here http://github.com/dpp/liftweb/issues ...
whether or not this solution will make it in master will be subject
for reviewboard. The solution I proposed has a breaking change by the
introduction of Either[List[String], LiftResponse] instead of
LiftResponse but I don't think that many people are using uriNotFound
and it's really quite a small change which regardless needs to be
announced.
Other opinions on this?
Br's,
Marius
--
You received this message because you are subscribed to the Google Groups "Lift" group.
To post to this group, send email to lif...@googlegroups.com.
To unsubscribe from this group, send email to liftweb+u...@googlegroups.com.
What about Either[RewriteResponse, LiftResponse]? E.g. same as what
Marius suggested but use RewriteResponse instead of String.
Overall this feature seems most similar to 'rewriting'. E.g. the url
comes in as "http://localhost/foobar", we don't recognize it, so we'll
re-write it to template "404".
I didn't say it was. I just said it seemed most similar to re-writing.
> Trying to mix the two will muddy the concept of rewriting and when it
> happens.
Makes sense.
> As far as I can tell, the two problems you are facing are:
>
> 1. There's a non-trivial amount of your code that needs to run to render
> the 404 error page. This would be corrected by the suggestion that I posted
> regarding a LiftRule that generates the default 404 template.
> 2. Putting navigation on the page. I'm still noodling how to address
> this particular issue.
>
> If there are issues other than 1 and 2, please enumerate them.
>
Those do sound like the issues. Just to reflect it back to you from
my perspective (in case one of us is missing something), the issue as
I see it is that I've designed a nice 404 template using lift features
(like surround, sitemap, headmerge), and I'd like to display it to the
user when no handler can be found
Whats preventing me from doing this is: the current notfound mechanism
takes a liftResponse, not a template to render, and as such forces me
to render the template itself, and although Russ proposed a way to do
that Marius indicated this could have side effects and feels like the
wrong approach.
> > liftweb+u...@googlegroups.com<liftweb%2Bunsu...@googlegroups.com>
> > .
> > > > For more options, visit this group athttp://
> > groups.google.com/group/liftweb?hl=en.
>
> > --
>
> > You received this message because you are subscribed to the Google Groups
> > "Lift" group.
> > To post to this group, send email to lif...@googlegroups.com.
> > To unsubscribe from this group, send email to
> > liftweb+u...@googlegroups.com<liftweb%2Bunsu...@googlegroups.com>
> > .
> > For more options, visit this group at
> >http://groups.google.com/group/liftweb?hl=en.
>
> --
> Lift, the simply functional web frameworkhttp://liftweb.net
> Beginning Scalahttp://www.apress.com/book/view/1430219890
To unsubscribe from this group, send email to liftweb+u...@googlegroups.com.
I noticed one issue: the head merge didn't get done, so I have two
<head> tags in the result. I'm attempting to set the title in the
404.html template, maybe there is a way I can set the title without
using head merge?
- Alex
On Dec 30, 2:54 pm, David Pollak <feeder.of.the.be...@gmail.com>
wrote:
> > <liftweb%2Bunsu...@googlegroups.com<liftweb%252Buns...@googlegroups.com>
>
> > > > .
> > > > > > For more options, visit this group athttp://
> > > > groups.google.com/group/liftweb?hl=en.
>
> > > > --
>
> > > > You received this message because you are subscribed to the Google
> > Groups
> > > > "Lift" group.
> > > > To post to this group, send email to lif...@googlegroups.com.
> > > > To unsubscribe from this group, send email to
> > > > liftweb+u...@googlegroups.com<liftweb%2Bunsu...@googlegroups.com>
> > <liftweb%2Bunsu...@googlegroups.com<liftweb%252Buns...@googlegroups.com>
But I'm still working on the solution I proposed which treats 404 as a
normal page. Not sure if Dave will like it (probably not) but I'll
send him a diff.
Br's,
Marius
> ...
>
> read more »
Ok, I tried this, it gets closer.
I noticed one issue: the head merge didn't get done, so I have two
<head> tags in the result. I'm attempting to set the title in the
404.html template, maybe there is a way I can set the title without
using head merge?
To unsubscribe from this group, send email to liftweb+u...@googlegroups.com.
Just curious though, is there any chance runTemplate should just do
the head merge?
On Dec 31, 3:12 pm, David Pollak <feeder.of.the.be...@gmail.com>
wrote:
> > > > <liftweb%2Bunsu...@googlegroups.com<liftweb%252Buns...@googlegroups.com>
> > <liftweb%252Buns...@googlegroups.com<liftweb%25252Bun...@googlegroups.com>
>
> > > > > > .
> > > > > > > > For more options, visit this group athttp://
> > > > > > groups.google.com/group/liftweb?hl=en.
>
> > > > > > --
>
> > > > > > You received this message because you are subscribed to the Google
> > > > Groups
> > > > > > "Lift" group.
> > > > > > To post to this group, send email to lif...@googlegroups.com.
> > > > > > To unsubscribe from this group, send email to
> > > > > > liftweb+u...@googlegroups.com<liftweb%2Bunsu...@googlegroups.com>
> > <liftweb%2Bunsu...@googlegroups.com<liftweb%252Buns...@googlegroups.com>
>
> > > > <liftweb%2Bunsu...@googlegroups.com<liftweb%252Buns...@googlegroups.com>
> > <liftweb%252Buns...@googlegroups.com<liftweb%25252Bun...@googlegroups.com>
David's solution is great and definitely works. But this thread made
me realize that a higher/easier level of addressing this is helpful.
From user perspective saying something like ".. .if a template cannot
be found, just use the template denominated by this path (i.e.
"foo" :: "bar" :: "404" :: Nil) instead.". Lift then would process
this template as the regular one with the difference that it will use
404 status code automatically.
Currently I have a prototype implementation and an offline discussion
with David about other more internal implications. We'll see where it
goes.
Br's,
Marius
> ...
>
> read more »
> ...
>
> read more »