美文网首页
SpringMVC版本升级带来的跨域处理异常

SpringMVC版本升级带来的跨域处理异常

作者: shuaipu | 来源:发表于2020-05-16 15:18 被阅读0次

问题

应项目要求,将工程中spring版本从[4.1.6.RELEASE]升级到[4.3.22.RELEASE],处理依赖冲突后,项目正常启动,大部分接口正常调用,部分接口异常,报错信息如下:

javax.servlet.ServletException: No adapter for handler [org.springframework.web.servlet.handler.AbstractHandlerMapping$PreFlightHandler@7e0b6142]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler
    at org.springframework.web.servlet.DispatcherServlet.getHandlerAdapter(DispatcherServlet.java:1202)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:947)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
    at com.vivo.framework.spring.webmvc.VivoDispatcherServlet.doService(VivoDispatcherServlet.java:96)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
    at org.springframework.web.servlet.FrameworkServlet.doOptions(FrameworkServlet.java:908)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:656)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)

定位分析

通过栈信息,跟踪到DispatcherServlet类,发现是No adapter for handler for PreFlightHandler,没有adapter处理options预请求。回看异常的接口,全部为跨域接口,且在发送doOptions阶段出现异常。代码如下:

/**
     * Return the HandlerAdapter for this handler object.
     * @param handler the handler object to find an adapter for
     * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
     */
    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        for (HandlerAdapter ha : this.handlerAdapters) {
            if (logger.isTraceEnabled()) {
                logger.trace("Testing handler adapter [" + ha + "]");
            }
            if (ha.supports(handler)) {
                return ha;
            }
        }
        throw new ServletException("No adapter for handler [" + handler +
                "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }

通过分别在4.16版本和4.3.2.2版本断点调试,比对发现,两版中,默认HandlerAdapter实现类均为RequestMappingHandlerAdapter,但4.16版本options预请求处理类为HandlerMethod,而4.3.22版本中为AbstractHandlerMapping$PreFlightHandler,RequestMappingHandlerAdapter不支持处理PreFlightHandler,所以报出该异常。

解决办法(二选一)

  • spring配置文件中增加如下配置,框架会自动实例化HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter这两个bean,其中HttpRequestHandlerAdapter可以处理options预请求
<mvc:annotation-driven>
  • 手动配置HttpRequestHandlerAdapter的bean
 <bean id="httpRequestHandlerAdapter" class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>

总结

SpringMVC处理Options类型的请求,需要HttpRequestHandlerAdapter,如果没有就会抛异常

拓展

浏览器将CORS请求分为两类:简单请求(simple request)和非简单请求(not-simple-request),简单请求不会doOptions,而非简单请求会doOptions。区分条件如下:

同时满足下列三大条件,就属于简单请求,否则属于非简单请求

  • 请求方式只能是:GET、POST、HEAD
  • HTTP请求头限制这几种字段:Accept、Accept-Language、Content-Language、Content-Type、Last-Event-ID
  • Content-type只能取:application/x-www-form-urlencoded、multipart/form-data、text/plain

典型非简单请求如,Content-type为application/json或自定义header,这些发生跨域请求时均需预请求一次。

相关文章

网友评论

      本文标题:SpringMVC版本升级带来的跨域处理异常

      本文链接:https://www.haomeiwen.com/subject/ebalohtx.html