为Jetty 9.4中发送的PUT请求到JSP显示自定义错误页面。

huangapple go评论85阅读模式
英文:

Show custom error page for PUT requests sent to JSP with Jetty 9.4

问题

背景

在从Spring 4升级到5.3时,web.xml中指定的错误页面不再适用于某些HTTP动词,其中之一是PUT。例如,当对Spring控制器发出PUT请求导致意外错误时,web.xml中定义的错误页面不会显示。相反,我们会得到类似于405 Method Not Allowed的错误。对于GET请求,错误页面显示正确。错误页面在web.xml中定义如下:

<error-page>
    <exception-type>java.lang.Exception</exception-type>
    <location>/uncaughtException</location>
</error-page>

“uncaughtException”是这样定义的tiles视图:

<definition extends="siteDefault" name="uncaughtException">
     <put-attribute name="body" value="/WEB-INF/views/uncaughtException.jspx"/>
</definition>

为了使所有HTTP动词都起作用,我们添加了这个Spring控制器:

@RequestMapping("/uncaughtException")
@Controller
public class UncaughtExceptionViewController {

    @RequestMapping
    public String uncaughtException() {
        return "uncaughtException";
    }

}

现在即使是PUT请求,错误页面也会正确显示。

以前我们使用Jetty 9.2,但在升级到Java 14时,我们也被迫升级到Jetty 9.4。在这样做时,我们注意到即使我们仍然有UncaughtExceptionViewController控制器,错误页面也不再显示PUT请求(对于GET请求有效)。相反,405 Method Not Allowed错误又出现了。在调试过程中,我们注意到在使用Jetty 9.4时,UncaughtExceptionViewController中的uncaughtException未被调用。

问题

我们如何配置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)
...
run:832, Thread (java.lang)
英文:

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:

&lt;error-page&gt;
    &lt;exception-type&gt;java.lang.Exception&lt;/exception-type&gt;
    &lt;location&gt;/uncaughtException&lt;/location&gt;
&lt;/error-page&gt;

"uncaughtException" is a tiles view defined like this:

&lt;definition extends=&quot;siteDefault&quot; name=&quot;uncaughtException&quot;&gt;
     &lt;put-attribute name=&quot;body&quot; value=&quot;/WEB-INF/views/uncaughtException.jspx&quot;/&gt;
&lt;/definition&gt;

To get this working for all HTTP verbs we added this Spring Controller:

@RequestMapping(&quot;/uncaughtException&quot;)
@Controller
public class UncaughtExceptionViewController {

    @RequestMapping
    public String uncaughtException() {
        return &quot;uncaughtException&quot;;
    }

}

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?

Update

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)

答案1

得分: 1

由于这是由JSP生成的。

可以使用标准的Servlet错误页面处理方式。

WEB-INF/web.xml 可以被定义用来响应状态码 405。

  &lt;error-page&gt;
    &lt;error-code&gt;405&lt;/error-code&gt;
    &lt;location&gt;/myMethodNotAllowedPath&lt;/location&gt;
  &lt;/error-page&gt;

你还可以选择性地定义一个全局错误页面处理程序,就像这样...

  &lt;error-page&gt;
    &lt;location&gt;/myGlobalErrorHandler&lt;/location&gt;
  &lt;/error-page&gt;

自Servlet 3.0起,&lt;error-page&gt; 可以基于状态码 &lt;error-code&gt;、异常 &lt;exception-type&gt; 或无任何定义(表示所有未被更具体定义捕获的错误)来定义反应。

Servlet实现将使用DispatcherType.ERROR重新分派请求到定义的&lt;location&gt;,原始请求的详细信息可以在HttpServletRequest.getAttribute(String) 的各个键/名称下找到,在RequestDispatcher.ERROR_* 常量中定义。

英文:

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.

  &lt;error-page&gt;
    &lt;error-code&gt;405&lt;/error-code&gt;
    &lt;location&gt;/myMethodNotAllowedPath&lt;/location&gt;
  &lt;/error-page&gt;

You can also, optionally, define a global error page error handler like this ..

  &lt;error-page&gt;
    &lt;location&gt;/myGlobalErrorHandler&lt;/location&gt;
  &lt;/error-page&gt;

Since Servlet 3.0, the &lt;error-page&gt; can define a reaction based on a status code &lt;error-code&gt;, an exception &lt;exception-type&gt;, or nothing (which means all errors not caught by more specific definitions)

The Servlet implementation will redispatch the request to the defined &lt;location&gt; 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.

huangapple
  • 本文由 发表于 2020年8月27日 21:55:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/63617584.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定