External redirects in exception logic is not working on Tomcat 8.5.39 - spring

I'm setting up exception handling logic for a multipart project with common error page (that is hosted in other part of the project). When I tried to redirect to external URL on exception, tomcat 8.5.39 is showing default error instead. Funny thing is, this seems to work just fine in tomcat 8.5.38
I've tried many different exception handling techniques, but they all seem not to work for external redirects.
So currently, i have something like this in my web.xml file:
...
<error-page>
<error-code>404</error-code>
<location>/error/error404</location>
</error-page>
...
and for my Spring controller,
#Controller
#RequestMapping(value = "/error")
public class ErrorHandler{
...
#GetMapping(value = "error404")
public String error404(){
return "redirect:http://{myproject}/{404errorPage}";
}
...
}
I'm expecting this code to redirect the user to http://{myproject}/{404errorPage} when 404 error occurs, which works just fine in tomcat 8.5.38. But on 8.5.39, they seem to have changed error handling logic, and it will display default error page(browser default 404 page).
Any input or idea would be tremendously helpful.

This is a known regression in 8.5.39 which is fixed in the just released 8.5.40.

Related

Spring MVC: how to handle incoming request to wrong context path

How do we handle incoming request to a wrong contextpath in spring mvc?
I have deployed a spring mvc application having contextpath as
http://exampledomain.com/mycontext
But when I try accessing url http://exampledomain.com/wrongcontext I get error as HTTP Status 404 - /wrongcontext/
I have implemented error handling which works fine for all wrong url when correct context path is used but it does not work for wrong context path.
I am trying to understand how do we redirect all incoming request to specific page in production environment..
thanks in advance
Your application can only see requests to its context /mycontext There is nothing your application can do about requests to other contexts.
You can however deploy an application at the root context / and implement an error handler there.
Check out this answer: How to customize JBoss AS7 404 page
That answer relates to JBoss, but the same idea will apply on other servers.
It is not possible to handle wrong context path requests in Spring since it only will handle the requests which goes to your context root. You have to take a look at server configuration parameters to redirect those kind of requests. If you are working on Tomcat, check path parameter of context.xml:
https://tomcat.apache.org/tomcat-7.0-doc/config/context.html#Defining_a_context
We can use #ExceptionHandler inside a #Controller or #ControllerAdvice to handle such kind of exceptions and decide on the view page to be rendered.
#ExceptionHandler({ HttpRequestMethodNotSupportedException.class,
HttpMediaTypeNotSupportedException.class, HttpMediaTypeNotAcceptableException.class,
MissingPathVariableException.class, MissingServletRequestParameterException.class,
ServletRequestBindingException.class,MethodArgumentNotValidException.class, MissingServletRequestPartException.class,
NoHandlerFoundException.class})
public ModelAndView handleException(){
return new ModelAndView("errorpage");
}

How to send the send status code as response for 404 instead of 404.jsp as a html reponse in spring?

I created web application in spring and handled exception mappings for 404 and 500.If system doesn't find any resources for requested URL it redirects into custom 404.jsp instead of regular 404 page.Everything works fine till have decided to add a webservice in my app.I have included one more controller as a webservice there is no view for this controller and this needs to be invoke through curl command.
User may get into change the curl script.If they changed the URL it should show 404 status code.But it returns the custom 404.jsp as a html response instead of status code.Because dispatcher servlet will takes all urls with /*.
How I can solve this issue?
Please share your suggestions.
Spring 3.2 introduced the #ControllerAdvice, and as mentioned in the documentation:
It is typically used to define #ExceptionHandler
That means you can use the #ControllerAdvice to assist your #Controller like the following:
#ControllerAdvice
class GlobalControllerExceptionHandler {
#ResponseStatus(HttpStatus.NOT_FOUND) // 404
#ExceptionHandler(Exception.class)
public void handleNoTFound() {
// Nothing to do
}
}
For further details please refer to this tutorial and this answer.

#ExceptionHandler + #ResponseStatus

I am handling my controlled exceptions using the following code:
#ExceptionHandler(MyException.class)
#ResponseStatus(HttpStatus.NOT_FOUND)
public ModelAndView handleMyException(MyException e) {
ModelAndView mav = new ModelAndView(ERROR_PAGE);
(...)
return mav;
}
That is, I want to both use custom views for different errors AND use response status code for the HTTP response.
At the same time, for pure 404 I have the following config in web.xml
<error-page>
<error-code>404</error-code>
<location>/404</location>
</error-page>
<error-page>
<error-code>400</error-code>
<location>/400</location>
</error-page>
Which takes to a 404 specific view.
The problem is that when a NOT_FOUND is thrown from my #ExceptionHandled method, it is not showing my custom view, debugging shows that execution actually goes through the handleMyException method, but after it's done it also goes through the method that maps the /404 in web.xml, and that is the view that gets shown.
Also if I throw a different Response Code, I get the default behavior on Exceptions, instead of my custom view.
I can't reproduce your problem with Tomcat 6 ans Spring 2.3.4. That is correct, because accroding to Servlet specification 2.5, the deployment descriptor defines a list of error
page descriptions. The syntax allows the configuration of resources to be returned
by the container either when a servlet or filter calls sendError
on the response for specific status codes (...)
I tracked where Spring sets response code basing on #ResponseStatus(HttpStatus.NOT_FOUND)
It is here:
public class ServletInvocableHandlerMethod (...)
private void setResponseStatus(ServletWebRequest webRequest) throws IOException {
if (this.responseStatus == null) {
return;
}
if (StringUtils.hasText(this.responseReason)) {
webRequest.getResponse().sendError(this.responseStatus.value(), this.responseReason);
}
else {
webRequest.getResponse().setStatus(this.responseStatus.value());
}
// to be picked up by the RedirectView
webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, this.responseStatus);
}
In my case if error handler method is annotated
#ResponseStatus(HttpStatus.NOT_FOUND)
the following branch is selected:
else {
webRequest.getResponse().setStatus(this.responseStatus.value());
}
Because HttpServletResponse.setStatus is called and NOT HttpServletResponse.sendError, web container ignores error page defined in <error-code>404</error-code>
I hope my explanation will be useful to track the problem yourself. I suspect somewhere HttpServletResponse.sendError is called and it triggers web container to return default error page
It sounds like the problem is probably that the web container is trying to handle the 400/404's its seeing from the web application (because it doesn't understand the context of those errors). You probably need to get rid of the web.xml error page definitions and add more configuration to the Spring controllers to handle the generic 400/404 errors as well.
This guide helped me a lot when I was setting up exception handling in my app: http://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
The web.xml tells the app container how to handle various response codes that are generated by the application. When you get an exception out of a controller method, it gets handled by the Spring #ExceptionHandler annotated method. At this point, the app container isn't involved so it has no idea what's going on yet.
My best understanding is that when you generate a 404 Http status from the exception handler method and return, Spring's basically done at that point, and the app container steps back in and says "I got a 404, what do I do with a 404? ah, redirect to /404". And then, control goes back to the web app itself to handle the /404 request.

HTTP Status 500 customise through webapp error page

I have customized error code 403 (client error) through webapp i.e. adding entry in web.xml as below which works fine.
<error-page>
<error-code>403</error-code>
<location>/access-denied.xhtml</location>
</error-page>
I try to customise error code 500 (server error) with the above approach as below.
<error-page>
<error-code>500</error-code>
<location>/error-500.xhtml</location>
</error-page>
but this doesn’t work (getting jboss's original error message for error code 500 instead of error-500.xhtml) and I have no clue why, so I am left with only option to customize it through apache httpd and vhost config.
Any idea why this is not working?
The reason for not working is because the webapp has implemented ExceptionMapper that catches the exception instead of letting the custom error page to be resolved from web.xml
The resolution would be to remove the ExceptionMapper impl class.

Custom page not found and other error webpages in Spring 3.0

I want to display a custom 404 page not found error page (among others). I'm using Spring 3.0 and don't know how to do this.. I know I can specify a jsp page in web.xml to handle 404 errors. But I want Spring's environment for my error pages. So I tried simply returning a ModelAndView that's basically an error page. But the problem there is once I do this:
response.sendError(HttpServletResponse.SC_NOT_FOUND);
Then the whole request just gets forwarded back to the container's default 404 page. How are we supposed to handle error pages in Spring 3.0?
In Servlet 2.4, response.sendError() and response.setStatus() are treated differently. The former is handled by container, but the latter gives option to provide the response yourself. That means, you have to use response.setStatus(HttpServletResponse.SC_NOT_FOUND). Please also see How do I return a 403 Forbidden in Spring MVC?

Resources