spring 4 異常HttpMediaTypeNotAcceptableException解決方案

異常問題

jsp頁面ajax請求錯誤:406Not Acceptablehtml

 

wKiom1kb5h7yNEkbAAAgt_AA47w783.png

 

後臺代碼:前端

wKiom1kb5iiT6eUAAABWOxkD7h8707.png

[2017:05:1709:51:22]:Resolving exception from handler [publicjava.util.Map<java.lang.String, java.lang.Object> com.demo.controller.DemoController.findWxmpType()]:org.springframework.web.HttpMediaTypeNotAcceptableException: Could not findacceptable representationjava

 

項目環境

項目環境:spingMVC 4.1.3  + spring + mybatis + jsp + jqueryjquery

 

傳輸數據格式:jsonweb

 

debug調試ajax

 

【想直接看解決方案的,請直接到文章末尾處】spring

項目代碼及相關配置

spring MVC部分配置:json

<!-- 註解驅動 -->微信

   <mvc:annotation-driven>mybatis

      <!-- 若是自定義message-converters,默認的message-converters將失效 -->

      <mvc:message-converters>

        <!-- 定義文本轉化器 -->

        <bean class="org.springframework.http.converter.StringHttpMessageConverter">

           <constructor-arg index="0"value="UTF-8" />

        </bean>

      </mvc:message-converters>

   </mvc:annotation-driven>

 

   <!-- 定義Controller的掃描包 -->

   <context:component-scan base-package="com.demo.controller"/>

   <!-- 定義視圖解析器 -->

   <bean

   class="org.springframework.web.servlet.view.InternalResourceViewResolver">

      <property name="prefix"value="/WEB-INF/pages/" />

      <property name="suffix"value=".jsp" />

   </bean>

 

   <!-- 處理靜態資源被「/」所攔截的問題 -->

   <mvc:default-servlet-handler />

web.xml部分配置:

<!-- 加載spring配置文件 -->

   <context-param>

      <param-name>contextConfigLocation</param-name>

      <param-value>classpath:spring/applicationContext*.xml</param-value>

   </context-param>

 

   <!--SpringApplicationContext 載入:Spring的監聽器 -->

   <listener>

   <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

   </listener>

 

 

   <!-- 加載SpringMVC的配置文件 -->

   <servlet>

      <servlet-name>demo</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

      <init-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>classpath:spring/demo-servlet.xml</param-value>

      </init-param>

      <load-on-startup>1</load-on-startup>

   </servlet>

   <!-- 配置訪問映射的視圖路徑和後綴 -->

   <servlet-mapping>

      <servlet-name>demo</servlet-name>

      <url-pattern>*.html</url-pattern>

   </servlet-mapping>

<!—全部請求 -->

   <!--<servlet-mapping>

      <servlet-name>demo</servlet-name>

      <url-pattern>/</url-pattern>

   </servlet-mapping>-->

jsp頁面:

   $.post(path+"/wxmp/findWxmpType.html",function(data){

alert(data);

      console.info("msg:"+data.msg);

      if(data.msg=="success"){

      alert(data.msg);

}})

Controller代碼:

@RequestMapping(value = "/findWxmpType", method =RequestMethod.POST)

   @ResponseBody

   publicMap<String, Object> findWxmpType() {

     Long startTime = System.currentTimeMillis();

     Map<String,Object> maps= newHashMap<String, Object>();

     try {

        // 微信公衆號搜索列表

        maps.put("msg", "success");

        LOGGER.debug("響應結果:maps{}", maps);

     } catch (Exception e) {

        LoggerUtil.errorLog("執行失敗", startTime, System.currentTimeMillis(),

             LOGGER, e);

        maps.put("msg", "加載數據異常,請稍後再試");

     }

     returnmaps;

   }

問題跟蹤分析

經過debug跟蹤,controller返回map集合數據是沒有問題的。

問題點出在:springMVC在對返回數據進行轉換處理的過程當中!

網上百度了一下方法:

1,controller返回的對象中必須包含getter/setter方法;(這個並非問題緣由)

2,  controller@RequestMapping(value= "/findWxmpType", method = RequestMethod.POST,produces="application/json")

加上紅色字體部分。並無解決問題,produces這個屬性,你們能夠百度下其具體做用是什麼。簡單來講:就是用於匹配頁面的請求頭Accept信息是否和響應頭Accept信息(produces設置)一致。

3,配置jackson轉換器,指定返回數據類型爲text/html;

<bean id="jacksonMessageConverter"

                                     class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">

                                     <!--解決 HttpMediaTypeNotAcceptableException: Could not findacceptable

                                               representation -->

                                     <propertyname="supportedMediaTypes">

                                               <list>

                                                        <value>text/html;charset=UTF-8</value>

                                                        <!--<value>application/json;charset=UTF-8</value> -->

                                               </list>

                                     </property>

                            </bean>

這個解決方案,配置後運行效果以下:

wKiom1kb5k2DaA3GAAAHIjXYOEQ289.png

wKioL1kb5j7SPH-LAAAEh0Pi-Hg195.png

數據是能夠進行傳輸了,但已經不是json格式,jsp沒法直接取到msg數據。

so,並無解決問題!!!刪除配置!

問題本質

springMVC在處理返回數據的時候是經過轉換器HttpMessageConverter進行處理的。

org.springframework.web.HttpMediaTypeNotAcceptableException:Could not find acceptable representation

這個錯誤是:不能找到能接受的HttpMediaType協議。也就是說jsp頁面的請求頭Accept信息和controller返回的響應頭accept頭信息不一致。

前端jspAccept頭信息:匹配全部。

wKiom1kb5l7ymxENAAB0sUrL01o112.png

更改配置

指定MediaTypesjson

wKioL1kb5mjSog8tAAA3vvL-XIY358.png

進入HttpMessageConverter轉換器源碼中:

插入一個小話題,eclipse跟蹤異常源碼方法:

wKiom1kb5nLAh0odAAAqcvIYbr8457.png

點擊藍色部分:彈框:

wKioL1kb5nuAssElAABG1ppgOJM141.png

點擊OK

源碼跟蹤

從新訪問頁面,進入debug斷點:

wKioL1kb5oaQ4G9JAACld97FHb4479.png

跟蹤A

@Override

       public List<MediaType>resolveMediaTypes(NativeWebRequest webRequest) throwsHttpMediaTypeNotAcceptableException {

              for (ContentNegotiationStrategystrategy : this.contentNegotiationStrategies) {

                     List<MediaType>mediaTypes = strategy.resolveMediaTypes(webRequest);

                     if (mediaTypes.isEmpty() ||mediaTypes.equals(MEDIA_TYPE_ALL)) {

                            continue;

                     }

                     return mediaTypes;

              }

              return Collections.emptyList();

       }

跟蹤BresolveMediaTypes(webRequest);

 

@Override

       public List<MediaType>resolveMediaTypes(NativeWebRequest webRequest) throwsHttpMediaTypeNotAcceptableException {

              String key =getMediaTypeKey(webRequest);

              if (StringUtils.hasText(key)) {

                     MediaType mediaType =lookupMediaType(key);

                     if (mediaType != null) {

                            handleMatch(key,mediaType);

                            returnCollections.singletonList(mediaType);

                     }

                     mediaType =handleNoMatch(webRequest, key);

                     if (mediaType != null) {

                            addMapping(key,mediaType);

                            returnCollections.singletonList(mediaType);

                     }

              }

              return Collections.emptyList();

       }

跟蹤C:getMediaTypeKey(webRequest);從當前請求request當中獲取到MediaType

wKiom1kb5pWgHX6XAABizm5zORQ591.png

@Override

       protected String getMediaTypeKey(NativeWebRequestwebRequest) {

              //獲取request對象

              HttpServletRequest servletRequest= webRequest.getNativeRequest(HttpServletRequest.class);

              if (servletRequest == null) {

                     logger.warn("AnHttpServletRequest is required to determine the media type key");

                     return null;

              }

              //獲取當前請求路徑:/wxmp/searchWxmps.html

              String path =urlPathHelper.getLookupPathForRequest(servletRequest);

              //獲取searchWxmps.html

              String filename =WebUtils.extractFullFilenameFromUrlPath(path);

              //獲取請求後綴:html

              String extension =StringUtils.getFilenameExtension(filename);

              return(StringUtils.hasText(extension)) ? extension.toLowerCase(Locale.ENGLISH) :null;

       }

wKioL1kb5rfCJYzvAAB9eeuMIc4026.png

 

回到:跟蹤B

wKioL1kb5sPTIgHdAABFtgeZw1w650.png

下一步:

wKiom1kb5tOA2iq2AABkTKn838Q994.png

而後返回MediaType

回到:跟蹤A

wKiom1kb5t-iBi9dAABUdgz71Vs908.png

下一步:直到ProducesRequestConverter:

wKiom1kb5uqinG0ZAABxYoXUcE0289.png

下一步:

wKiom1kb5vSwspJ4AABg-UltX8Y749.png

@Override

              protected booleanmatchMediaType(HttpServletRequest request) throwsHttpMediaTypeNotAcceptableException {

              //acceptedMediaTypes=text/html 在通過springMVC解析以後的,頁面想要的數據頭信息

List<MediaType> acceptedMediaTypes =getAcceptedMediaTypes(request);

                    

                     for (MediaTypeacceptedMediaType : acceptedMediaTypes) {

 // getMediaType()=application/json咱們配置的<value>application/json;charset=UTF8</value>

                            if(getMediaType().isCompatibleWith(acceptedMediaType)) {

                                   return true;

                            }

                     }

                     return false;

              }

結果就是:

wKioL1kb5xuwgnRZAABWOxkD7h8442.png

 

結論

在從jsp頁面發送ajax請求的時候,代碼是:

$.post(path+"/wxmp/findWxmpType.html",function(data){}

請求路徑爲:http://m.demo.com/wxmp/findWxmpType.html這個後綴「.html」就是問題的根源。

該方法實際上只是爲了請求數據,徹底能夠不帶「.html,可是在web.xml裏面,進行的僞靜態訪問配置<servlet-mapping>

由於該配置,全部的訪問,必須加上後綴「.html」才能進入後臺。

帶上這個配置以後,springMVC在解析前臺請求頭信息Accept的時候,本來是:*/* ,卻解析成了:text/html

這樣的話,咱們在controller中加上@ResponseBody對返回數據進行json轉換,設置響應頭Accept=application/json以後,匹配matchProduces異常。

 

解決辦法

1web.xml中添加這段配置:

 

<!—全部請求可進入 -->

       <servlet-mapping>

              <servlet-name>wupao-mwss</servlet-name>

              <url-pattern>/</url-pattern>

       </servlet-mapping>

也就是放開 前文web.xml中最後的註釋部分便可。

 

2jsp頁面請求更改成:$.post(path+"/wxmp/findWxmpType",function(data){}

去掉.html便可解決問題!!!

相關文章
相關標籤/搜索