Reputation: 40510
Background
When upgrading from Spring 4 to 5.3 the error page specified in web.xml
no longer worked for certain HTTP verbs, one of these was PUT
. For example, when a PUT
request to a Spring controller resulted in an unexpected error, the error page defined in web.xml
was not shown. Instead, we got an error along the lines of 405 Method Not Allowed
. The error page was shown correctly for GET
requests. The error page was (and is still) defined like this in web.xml
:
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/uncaughtException</location>
</error-page>
"uncaughtException" is a tiles view defined like this:
<definition extends="siteDefault" name="uncaughtException">
<put-attribute name="body" value="/WEB-INF/views/uncaughtException.jspx"/>
</definition>
To get this working for all HTTP verbs we added this Spring Controller:
@RequestMapping("/uncaughtException")
@Controller
public class UncaughtExceptionViewController {
@RequestMapping
public String uncaughtException() {
return "uncaughtException";
}
}
Now the error page was shown correctly even for PUT
requests.
Previously we used Jetty 9.2 but when upgrading to Java 14 we were also forced to upgrade to Jetty 9.4. When doing this we noticed that the error page was no longer shown for PUT
requests (it works for GET
) even though we still have the UncaughtExceptionViewController
controller. Instead, the 405 Method Not Allowed
error is back. During debugging we noticed that the uncaughtException
in UncaughtExceptionViewController
is not called when using Jetty 9.4.
Question
How can we configure Jetty or Spring MVC to show the error page even for PUT
requests and not only for GET
and not show us 405 Method Not Allowed
?
After setting a break-point in org.eclipse.jetty.server.Response.setStatus
I see that the problem seems to be that "JSPs only permit GET, POST or HEAD. Jasper also permits OPTIONS". The full stack-trace is:
sendError:454, Response (org.eclipse.jetty.server)
sendError:158, HttpServletResponseWrapper (javax.servlet.http)
sendError:119, OnCommittedResponseWrapper (org.springframework.session.web.http)
sendError:158, HttpServletResponseWrapper (javax.servlet.http)
sendError:158, HttpServletResponseWrapper (javax.servlet.http)
sendError:119, OnCommittedResponseWrapper (org.springframework.security.web.util)
sendError:158, HttpServletResponseWrapper (javax.servlet.http)
sendError:119, OnCommittedResponseWrapper (org.springframework.security.web.util)
_jspService:1, site_005fdefault_jspx (org.apache.jsp.WEB_002dINF.layouts)
service:71, HttpJspBase (org.apache.jasper.runtime)
service:790, HttpServlet (javax.servlet.http)
service:476, JspServletWrapper (org.apache.jasper.servlet)
serviceJspFile:386, JspServlet (org.apache.jasper.servlet)
service:330, JspServlet (org.apache.jasper.servlet)
service:106, JettyJspServlet (org.eclipse.jetty.jsp)
service:790, HttpServlet (javax.servlet.http)
service:1402, ServletHolder$NotAsyncServlet (org.eclipse.jetty.servlet)
handle:763, ServletHolder (org.eclipse.jetty.servlet)
doHandle:569, ServletHandler (org.eclipse.jetty.servlet)
handle:143, ScopedHandler (org.eclipse.jetty.server.handler)
handle:620, SecurityHandler (org.eclipse.jetty.security)
handle:127, HandlerWrapper (org.eclipse.jetty.server.handler)
nextHandle:235, ScopedHandler (org.eclipse.jetty.server.handler)
doHandle:1610, SessionHandler (org.eclipse.jetty.server.session)
nextHandle:233, ScopedHandler (org.eclipse.jetty.server.handler)
doHandle:1377, ContextHandler (org.eclipse.jetty.server.handler)
nextScope:188, ScopedHandler (org.eclipse.jetty.server.handler)
doScope:507, ServletHandler (org.eclipse.jetty.servlet)
doScope:1580, SessionHandler (org.eclipse.jetty.server.session)
nextScope:186, ScopedHandler (org.eclipse.jetty.server.handler)
doScope:1292, ContextHandler (org.eclipse.jetty.server.handler)
handle:141, ScopedHandler (org.eclipse.jetty.server.handler)
forward:219, Dispatcher (org.eclipse.jetty.server)
forward:78, Dispatcher (org.eclipse.jetty.server)
forward:407, SessionRepositoryFilter$SessionRepositoryRequestWrapper$SessionCommittingRequestDispatcher (org.springframework.session.web.http)
forward:265, ServletRequest (org.apache.tiles.request.servlet)
doForward:228, ServletRequest (org.apache.tiles.request.servlet)
dispatch:57, AbstractClientRequest (org.apache.tiles.request)
render:47, DispatchRenderer (org.apache.tiles.request.render)
render:259, BasicTilesContainer (org.apache.tiles.impl)
render:397, BasicTilesContainer (org.apache.tiles.impl)
render:238, BasicTilesContainer (org.apache.tiles.impl)
render:221, BasicTilesContainer (org.apache.tiles.impl)
render:59, DefinitionRenderer (org.apache.tiles.renderer)
renderMergedOutputModel:147, TilesView (org.springframework.web.servlet.view.tiles3)
render:316, AbstractView (org.springframework.web.servlet.view)
render:1373, DispatcherServlet (org.springframework.web.servlet)
processDispatchResult:1118, DispatcherServlet (org.springframework.web.servlet)
doDispatch:1057, DispatcherServlet (org.springframework.web.servlet)
doService:943, DispatcherServlet (org.springframework.web.servlet)
processRequest:1006, FrameworkServlet (org.springframework.web.servlet)
doPut:920, FrameworkServlet (org.springframework.web.servlet)
service:710, HttpServlet (javax.servlet.http)
service:883, FrameworkServlet (org.springframework.web.servlet)
service:790, HttpServlet (javax.servlet.http)
handle:763, ServletHolder (org.eclipse.jetty.servlet)
doFilter:1651, ServletHandler$CachedChain (org.eclipse.jetty.servlet)
doFilter:226, WebSocketUpgradeFilter (org.eclipse.jetty.websocket.server)
doFilter:1638, ServletHandler$CachedChain (org.eclipse.jetty.servlet)
doFilterInternal:186, OpenEntityManagerInViewFilter (org.springframework.orm.jpa.support)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
doFilter:1638, ServletHandler$CachedChain (org.eclipse.jetty.servlet)
doFilter:317, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
invoke:127, FilterSecurityInterceptor (org.springframework.security.web.access.intercept)
doFilter:91, FilterSecurityInterceptor (org.springframework.security.web.access.intercept)
doFilter:331, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilter:114, ExceptionTranslationFilter (org.springframework.security.web.access)
doFilter:331, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilter:137, SessionManagementFilter (org.springframework.security.web.session)
doFilter:331, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilter:111, AnonymousAuthenticationFilter (org.springframework.security.web.authentication)
doFilter:331, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilter:158, RememberMeAuthenticationFilter (org.springframework.security.web.authentication.rememberme)
doFilter:331, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilter:170, SecurityContextHolderAwareRequestFilter (org.springframework.security.web.servletapi)
doFilter:331, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilter:63, RequestCacheAwareFilter (org.springframework.security.web.savedrequest)
doFilter:331, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilterInternal:158, BasicAuthenticationFilter (org.springframework.security.web.authentication.www)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
doFilter:331, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilter:200, AbstractAuthenticationProcessingFilter (org.springframework.security.web.authentication)
doFilter:331, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilter:116, LogoutFilter (org.springframework.security.web.authentication.logout)
doFilter:331, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilterInternal:66, HeaderWriterFilter (org.springframework.security.web.header)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
doFilter:331, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilterInternal:56, WebAsyncManagerIntegrationFilter (org.springframework.security.web.context.request.async)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
doFilter:331, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilter:105, SecurityContextPersistenceFilter (org.springframework.security.web.context)
doFilter:331, FilterChainProxy$VirtualFilterChain (org.springframework.security.web)
doFilterInternal:214, FilterChainProxy (org.springframework.security.web)
doFilter:177, FilterChainProxy (org.springframework.security.web)
invokeDelegate:358, DelegatingFilterProxy (org.springframework.web.filter)
doFilter:271, DelegatingFilterProxy (org.springframework.web.filter)
doFilter:1638, ServletHandler$CachedChain (org.eclipse.jetty.servlet)
doFilterInternal:94, HiddenHttpMethodFilter (org.springframework.web.filter)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
doFilter:1638, ServletHandler$CachedChain (org.eclipse.jetty.servlet)
doFilterInternal:201, CharacterEncodingFilter (org.springframework.web.filter)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
doFilter:1638, ServletHandler$CachedChain (org.eclipse.jetty.servlet)
doFilterInternal:40, CorsFilter (com.mycompany.spring)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
doFilter:1638, ServletHandler$CachedChain (org.eclipse.jetty.servlet)
doFilterInternal:141, SessionRepositoryFilter (org.springframework.session.web.http)
doFilter:82, OncePerRequestFilter (org.springframework.session.web.http)
invokeDelegate:358, DelegatingFilterProxy (org.springframework.web.filter)
doFilter:271, DelegatingFilterProxy (org.springframework.web.filter)
doFilter:1638, ServletHandler$CachedChain (org.eclipse.jetty.servlet)
doHandle:567, ServletHandler (org.eclipse.jetty.servlet)
handle:143, ScopedHandler (org.eclipse.jetty.server.handler)
handle:578, SecurityHandler (org.eclipse.jetty.security)
handle:127, HandlerWrapper (org.eclipse.jetty.server.handler)
nextHandle:235, ScopedHandler (org.eclipse.jetty.server.handler)
doHandle:1610, SessionHandler (org.eclipse.jetty.server.session)
nextHandle:233, ScopedHandler (org.eclipse.jetty.server.handler)
doHandle:1377, ContextHandler (org.eclipse.jetty.server.handler)
nextScope:188, ScopedHandler (org.eclipse.jetty.server.handler)
doScope:507, ServletHandler (org.eclipse.jetty.servlet)
doScope:1580, SessionHandler (org.eclipse.jetty.server.session)
nextScope:186, ScopedHandler (org.eclipse.jetty.server.handler)
doScope:1292, ContextHandler (org.eclipse.jetty.server.handler)
handle:141, ScopedHandler (org.eclipse.jetty.server.handler)
handle:191, ContextHandlerCollection (org.eclipse.jetty.server.handler)
handle:146, HandlerCollection (org.eclipse.jetty.server.handler)
handle:127, HandlerWrapper (org.eclipse.jetty.server.handler)
handle:501, Server (org.eclipse.jetty.server)
lambda$handle$1:383, HttpChannel (org.eclipse.jetty.server)
dispatch:-1, 435181768 (org.eclipse.jetty.server.HttpChannel$$Lambda$1064)
dispatch:556, HttpChannel (org.eclipse.jetty.server)
handle:375, HttpChannel (org.eclipse.jetty.server)
onFillable:273, HttpConnection (org.eclipse.jetty.server)
succeeded:311, AbstractConnection$ReadCallback (org.eclipse.jetty.io)
fillable:105, FillInterest (org.eclipse.jetty.io)
run:104, ChannelEndPoint$1 (org.eclipse.jetty.io)
runTask:336, EatWhatYouKill (org.eclipse.jetty.util.thread.strategy)
doProduce:313, EatWhatYouKill (org.eclipse.jetty.util.thread.strategy)
tryProduce:171, EatWhatYouKill (org.eclipse.jetty.util.thread.strategy)
produce:135, EatWhatYouKill (org.eclipse.jetty.util.thread.strategy)
run:-1, 976266910 (org.eclipse.jetty.io.ManagedSelector$$Lambda$1056)
runJob:806, QueuedThreadPool (org.eclipse.jetty.util.thread)
run:938, QueuedThreadPool$Runner (org.eclipse.jetty.util.thread)
run:832, Thread (java.lang)
Upvotes: 0
Views: 600
Reputation: 49462
Since this is produced by JSP.
The standard Servlet Error-Page handling can be used.
The WEB-INF/web.xml
can be defined to respond to status code 405.
<error-page>
<error-code>405</error-code>
<location>/myMethodNotAllowedPath</location>
</error-page>
You can also, optionally, define a global error page error handler like this ..
<error-page>
<location>/myGlobalErrorHandler</location>
</error-page>
Since Servlet 3.0, the <error-page>
can define a reaction based on a status code <error-code>
, an exception <exception-type>
, or nothing (which means all errors not caught by more specific definitions)
The Servlet implementation will redispatch the request to the defined <location>
with DispatcherType.ERROR
, and the details of the original request can be found in the HttpServletRequest.getAttribute(String)
values under the various keys/names defined in the RequestDispatcher.ERROR_*
constants.
Upvotes: 1