I work on a JSF application powered by Tomcat 7.0.35. I would like to create a custom error page and have therefore played with the <error-page>
tag in the web.xml
configuration file.
<error-page>
<error-code>404</error-code>
<location>/error</location>
</error-page>
It seems to work in the sense that in case of a 404, the page returned has the correct HTTP body. However the HTTP return code is 200. The expected 404 was correctly received when <error-page>
was not configured.
The same soft-404 problem happens if <error-code>
is not specified.
<error-page>
<location>/error</location>
</error-page>
I am looking for a way to configure this error page without losing the error code.
Two more pieces of information that might be useful :
Pretty URLs are being handled by Pretty Faces 3.3.3 with the following
@Named(value = "error")
@RequestScoped
@URLMappings(mappings = {
@URLMapping(id = "error", pattern = "/error", viewId = "/faces/error.xhtml")})
public class ErrorController implements Serializable {
Sometimes containers do not seem to behave very nicely when you have an Error page handled by a servlet filter. In this case it looks like you probably have mapped "/error" with PrettyFaces, and are forwarding that internally to another resource. (PrettyFaces works with Servlet forwards)
I believe what occurs here, is the container sees that new Forward, forgets that it was actually showing an error page, and sends a 200 status because the Forwarded request was successful.
What you will need to do to resolve this, is add an <action>#{bean.send404}</action>
that sets the 404 status in your error page prettyfaces mapping.
<url-mapping>
<pattern value="/error" />
<view-id="/faces/error.xhtml" />
<action>#{bean.send404}</action>
</url-mapping>
Then your bean method will need to get a hold of the HttpServletResponse, which ou can usually get from the FacesContext:
HttpServletResponse response = (HttpServletResponse)FacesContext.getCurrentInstance()
.getExternalContext().getResponse();
response.sendError(HttpServletResponse.SC_NOT_FOUND);
That should do the trick for you.