由於公司對SpingMVC框架里面的東西進行了擴展,在配置SpringMVC時沒有使用
<mvc:annotation-driven>
這個標簽。而且是自己手動來配置
HandlerMapping
和
HandlerAdapter
。在處理跨域請求時,就拋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)
x
1
threw exception [No adapter for handler [org.springframework.web.servlet.handler.AbstractHandlerMapping$PreFlightHandler ]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler] with root cause
2
javax.servlet.ServletException: No adapter for handler [org.springframework.web.servlet.handler.AbstractHandlerMapping$PreFlightHandler ]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler
3
at org.springframework.web.servlet.DispatcherServlet.getHandlerAdapter(DispatcherServlet.java:1202)
4
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:947)
5
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
6
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
7
at org.springframework.web.servlet.FrameworkServlet.doOptions(FrameworkServlet.java:908)
8
at javax.servlet.http.HttpServlet.service(HttpServlet.java:657)
9
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
10
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"/>
2
1
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>
2
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
三、小結
(1)SpringMVC處理Options類型的請求,需要HttpRequestHandlerAdapter,如果沒有就會拋異常
(2)當我們不使用
<
mvc:annotation-driven
>
這個標簽時,盡量手動把它會注冊的
HandlerAdapter
都注冊一遍,防止出現No adapter for handler的異常