1. 程式人生 > >spring 4 異常HttpMediaTypeNotAcceptableException解決方案

spring 4 異常HttpMediaTypeNotAcceptableException解決方案

springmvc4 httpmediatypenotacceptableexception 406 notaccepted

異常問題

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

技術分享

後臺代碼:

技術分享

[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 representation

項目環境

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

傳輸數據格式:json

debug調試

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

項目代碼及相關配置

spring MVC部分配置:

<!-- 註解驅動 -->

<mvc:annotation-driven>

<!-- 如果自定義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>

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

技術分享

技術分享

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

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

問題本質

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

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

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

前端jspAccept頭信息:匹配所有。

技術分享

更改配置

指定MediaTypesjson

技術分享

進入HttpMessageConverter轉換器源碼中:

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

技術分享

點擊藍色部分:彈框:

技術分享

點擊OK

源碼跟蹤

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

技術分享

跟蹤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

技術分享

@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;

}

技術分享

回到:跟蹤B

技術分享

下一步:

技術分享

然後返回MediaType

回到:跟蹤A

技術分享

下一步:直到ProducesRequestConverter:

技術分享

下一步:

技術分享

@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;

}

結果就是:

技術分享

結論

在從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即可解決問題!!!


本文出自 “IT技術解決方案” 博客,請務必保留此出處http://wyait.blog.51cto.com/12674066/1926619

spring 4 異常HttpMediaTypeNotAcceptableException解決方案