java - 显示使用 Jetty 9.4 发送到 JSP 的 PUT 请求的自定义错误页面
问题描述
背景
从 Spring 4 升级到 5.3 时,指定的错误页面web.xml
不再适用于某些 HTTP 动词,其中之一是PUT
. 例如,当PUT
对 Spring 控制器的请求导致意外错误时,web.xml
不会显示中定义的错误页面。相反,我们得到了一个错误405 Method Not Allowed
。错误页面已正确显示GET
请求。错误页面被(并且仍然)定义如下web.xml
:
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/uncaughtException</location>
</error-page>
“uncaughtException”是一个这样定义的图块视图:
<definition extends="siteDefault" name="uncaughtException">
<put-attribute name="body" value="/WEB-INF/views/uncaughtException.jspx"/>
</definition>
为了让所有 HTTP 动词都能正常工作,我们添加了这个 Spring Controller:
@RequestMapping("/uncaughtException")
@Controller
public class UncaughtExceptionViewController {
@RequestMapping
public String uncaughtException() {
return "uncaughtException";
}
}
现在,即使对于PUT
请求,错误页面也能正确显示。
以前我们使用 Jetty 9.2,但在升级到 Java 14 时,我们也被迫升级到 Jetty 9.4。执行此操作时,我们注意到错误页面不再显示PUT
请求(它适用于GET
),即使我们仍然拥有UncaughtExceptionViewController
控制器。相反,405 Method Not Allowed
错误又回来了。在调试过程中,我们注意到使用 Jetty 9.4 时没有调用uncaughtException
in 。UncaughtExceptionViewController
问题
我们如何配置 Jetty 或 Spring MVC 以显示错误页面,即使是PUT
请求,而不是只GET
显示也不显示405 Method Not Allowed
?
更新
在设置断点后,org.eclipse.jetty.server.Response.setStatus
我发现问题似乎是“JSP 只允许 GET、POST 或 HEAD。Jasper 也允许 OPTIONS”。完整的堆栈跟踪是:
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)
解决方案
由于这是由 JSP 产生的。
可以使用标准的 Servlet 错误页面处理。
WEB-INF/web.xml
可以定义为响应状态码 405 。
<error-page>
<error-code>405</error-code>
<location>/myMethodNotAllowedPath</location>
</error-page>
您还可以选择定义一个全局错误页面错误处理程序,如下所示..
<error-page>
<location>/myGlobalErrorHandler</location>
</error-page>
从 Servlet 3.0 开始,<error-page>
可以根据状态码<error-code>
、异常<exception-type>
或什么都没有定义反应(这意味着所有错误都没有被更具体的定义捕获)
Servlet 实现会将请求重新调度到定义<location>
的 with DispatcherType.ERROR
,原始请求的详细信息可以在常量HttpServletRequest.getAttribute(String)
中定义的各种键/名称下的值中找到。RequestDispatcher.ERROR_*
推荐阅读
- vue.js - 如果我们使用 `Filter()`,我们可以让 Vue 检测数组的变化吗?
- javascript - 如何将焦点设置在 PWA 中打开的窗口上?
- r - 在标题中使用常用字符在数据框中添加列值
- angularjs - 如何将 url 传递给 Angular js 工厂中存在的 $resource
- java - 为什么拖动这个jpanel会产生屏幕撕裂效果?
- python - 列表理解追加赔率两次偶数一次
- sql-server - Microsoft SQL Server Management Studio 中 CTE 的语法
- java - 未正确计算通过 Java 代码添加到组的用户的访问权限
- android - 如何在 android webview 中修复 NameNotFoundException
- python - 解决导入模块中的“ValueError:‘str’类型对象的未知格式代码‘f’”