SpringMVC处理跨域请求时的一个注意事项

Posted zeng1994

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringMVC处理跨域请求时的一个注意事项相关的知识,希望对你有一定的参考价值。

    由于公司对SpingMVC框架里面的东西进行了扩展,在配置SpringMVC时没有使用<mvc:annotation-driven>这个标签。而且是自己手动来配置HandlerMappingHandlerAdapter。在处理跨域请求时,就抛No adapter for handler 异常了。记录下该异常的解决过程,方便后续查询。

一、异常信息

    具体的异常信息如下:
threw exception [No adapter for handler [org.springframework.web.servlet.handler.AbstractHandlerMapping$PreFlightHandler@edcb4b4]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler] with root cause
javax.servlet.ServletException: No adapter for handler [org.springframework.web.servlet.handler.AbstractHandlerMapping$PreFlightHandler@edcb4b4]: 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 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:657)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)

二、问题的解决

(1)异常的分析
    分析上面的异常信息,发现是在doOptions没找到合适的HandlerAdapter。跨域请求时是会发送2个请求的,第一个是就是options类型的请求。所以这里的问题就是在处理options请求时。
    再看了下代码中配置的HandlerAdapter,配置代码如下图
    注册的HandlerAdapter实例为 RequestMappingHandlerAdapter于是我怀疑是这个RequestMappingHandlerAdapter不支持options类型的请求。
(2)验证自己的想法
    带着怀疑的想法,把xml配置中手动配置的HandlerAdapter给去掉了,然后加上<mvc:annotation-driven>这个标签。再运行项目,发现跨域请求居然可以处理了。说明确实是有handlerAdapter没有配置上去。
    debug了DispatcherServlet下里面的代码,发现处理options请求时需要的handlerAdapter是HttpRequestHandlerAdapter的实例。因此问题的根源就是我们的SpringMVC的配置中没有配置HttpRequestHandlerAdapter,导致没有找到支持options类型请求的handlerAdapter。
(3)解决问题
    由于框架的问题,不适合直接使用<mvc:annotation-driven>这个标签(用了会导致扩展的功能失效)。分析了<mvc:annotation-driven>这个标签可知它会实例化3个HandlerAdapter,而我的配置文件只实例化了一个RequestMappingHandlerAdapter。因此我把另外两个handlerAdapter的实例也添加到配置文件中了。另外2个handlerAdapter的其中之一就是HttpRequestHandlerAdapter,这个handlerAdapter就可以处理options请求。
    我把代码还原至没添加<mvc:annotation-driven>的状态,然后在注册RequestMappingHandlerAdapter的代码后面加上如下代码:
    <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

三、小结

    (1)SpringMVC处理Options类型的请求,需要HttpRequestHandlerAdapter,如果没有就会抛异常
    (2)当我们不使用<mvc:annotation-driven>这个标签时,尽量手动把它会注册的HandlerAdapter都注册一遍,防止出现No adapter for handler的异常


以上是关于SpringMVC处理跨域请求时的一个注意事项的主要内容,如果未能解决你的问题,请参考以下文章

http跨域时的options请求

SpringMVC原理操作流程,拦截器,过滤器,参数,跨域

前端处理跨域请求(含vue的处理方式)

使用 Spring MVC 4 处理跨域预检 AJAX OPTIONS 请求

ajax跨域请求的处理

SpringMVC-跨域请求