首页 > 代码库 > spring 4 异常HttpMediaTypeNotAcceptableException解决方案

spring 4 异常HttpMediaTypeNotAcceptableException解决方案

异常问题

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 = http://www.mamicode.com/"/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= "http://www.mamicode.com/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解决方案