• Spring MVC 以.html为后缀名访问获取数据,报406 Not Acceptable错误


    转载,感谢这位博主,有自己的添加。

    如题,最近以spring mvc作为后台框架,前端异步获取数据时(.html为后缀名的访问方式),报406 Not Acceptable错误。当初都不知道啥原因,前后台都没报错就是返回不了数据,于是查了下http 406响应码:406 (SC_NOT_ACCEPTABLE)表示请求资源的MIME类型与客户端中Accept头信息中指定的类型不一致。下面请看出错的操作流程及代码:

    1、先配置spring mvc 核心servlet (DispatcherServlet) 至web.xml中,其中配置可以以.html和.do为后缀名的请求。(注意:只显示重要代码,下面也是一样)

        <servlet>
            <servlet-name>DispatcherServlet</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:dispatcher-servlet.xml</param-value>
            </init-param>
        </servlet>
        <servlet-mapping>
            <servlet-name>DispatcherServlet</servlet-name>
            <url-pattern>*.html</url-pattern>
        </servlet-mapping>
        <servlet-mapping>
            <servlet-name>DispatcherServlet</servlet-name>
            <url-pattern>*.do</url-pattern>
        </servlet-mapping>

    2、controller部分代码如下:

        @RequestMapping(value="chat/startClient")
        @ResponseBody
        public AjaxResult startClient(UserEntity user,HttpServletRequest request) {
            AjaxResult result = new AjaxResult(1);
            if (user.getUserId() == null){
                user.setUserId(System.currentTimeMillis());
                SessionUtil.setAttr(request, SessionUtil.SESSION_USER, user);
            } else {
                UserEntity sessionUser = SessionUtil.getUser(request);
                if (sessionUser.getUserId().equals(user.getUserId())) {
                   user = sessionUser; 
                }
            }
            if (Client.startClient(user)) {
                result.setData(user);
            }
            return result;
        }

    3、jsp 异步请求代码如下:

      $.ajax({
        url:'${pageContext.request.contextPath}/chat/startClient.html',
           dataType: 'json',
           data:{userId:$("input[name=userId]").val(),userName:$("#userName").val()},
        success: function(result){
             var state = result.error;
              if(state == 1){
             $('.modal-header .close').click();
            $("input[name=userName]").val($("#userName").val());
          }
        }
      });

    配置以上代码启动项目访问上面jsp中的异步方法时,通过浏览器的开发者工具(google)查看请求结果如下,通过响应头来看Content-type确实不一样,返回的是text/html,而请求的是application/json,所以浏览器无法解析或者接受这样的类型,就报错406错误。

    针对上面情况在网上折腾了一会,终于找到了破解之法,该问题的主要原因:Spring MVC有点不一样,如果你没有配置什么样的请求方式对应什么样的响应方式的话,它会根据url的后缀名对应不同响应头的格式,如下:

    public class MediaType extends MimeType
      implements Serializable
    {
      private static final long serialVersionUID = 2069937152339670231L;
      public static final MediaType ALL = valueOf("*/*");
      public static final String ALL_VALUE = "*/*";
      public static final MediaType APPLICATION_ATOM_XML = valueOf("application/atom+xml");
      public static final String APPLICATION_ATOM_XML_VALUE = "application/atom+xml";
      public static final MediaType APPLICATION_FORM_URLENCODED = valueOf("application/x-www-form-urlencoded");
      public static final String APPLICATION_FORM_URLENCODED_VALUE = "application/x-www-form-urlencoded";
      public static final MediaType APPLICATION_JSON = valueOf("application/json");
      public static final String APPLICATION_JSON_VALUE = "application/json";
      public static final MediaType APPLICATION_OCTET_STREAM = valueOf("application/octet-stream");
      public static final String APPLICATION_OCTET_STREAM_VALUE = "application/octet-stream";
      public static final MediaType APPLICATION_XHTML_XML = valueOf("application/xhtml+xml");
      public static final String APPLICATION_XHTML_XML_VALUE = "application/xhtml+xml";
      public static final MediaType APPLICATION_XML = valueOf("application/xml");
      public static final String APPLICATION_XML_VALUE = "application/xml";
      public static final MediaType IMAGE_GIF = valueOf("image/gif");
      public static final String IMAGE_GIF_VALUE = "image/gif";
      public static final MediaType IMAGE_JPEG = valueOf("image/jpeg");
      public static final String IMAGE_JPEG_VALUE = "image/jpeg";
      public static final MediaType IMAGE_PNG = valueOf("image/png");
      public static final String IMAGE_PNG_VALUE = "image/png";
      public static final MediaType MULTIPART_FORM_DATA = valueOf("multipart/form-data");
      public static final String MULTIPART_FORM_DATA_VALUE = "multipart/form-data";
      public static final MediaType TEXT_HTML = valueOf("text/html");
      public static final String TEXT_HTML_VALUE = "text/html";
      public static final MediaType TEXT_PLAIN = valueOf("text/plain");
      public static final String TEXT_PLAIN_VALUE = "text/plain";
      public static final MediaType TEXT_XML = valueOf("text/xml");
      public static final String TEXT_XML_VALUE = "text/xml";
      private static final String PARAM_QUALITY_FACTOR = "q";
    }

    解决方法:所以我们要针对此情况进行配置,更改html对应返回的类型。(注意:1、先声明下我使用的spring 版本:4.1.9,2、如果想要使用@ResponseBody返回json格式,就需要加载这三个包:jackson-core、jackson-databind和jackson-annotations,请自行去mvn repository中获取) 一般我们是配置在mvc配置文件中需要配置<mvc:annotation-driven />, 所以我们只要修改下这里就行,修改配置代码如下:

        <mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />
        <!-- 以.html为后缀名访问,默认返回数据类型是 text/html, 所以要修改返回的数据类型 -->
        <bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean"> 
            <property name="mediaTypes">  
                <map>  
                    <entry key="html" value="application/json;charset=UTF-8"/> 
                </map>  
            </property> 
        </bean>

    ContentNegotiationManagerFactoryBean 是内容协商管理工厂bean对象,主要用来配置多视图请求格式。

    我的添加:除了这样,我们通过看

    content-negotiation-manager的注释我们知道,它是通过.html  .json来响应html还是json的,既然这样,我的所有json都使用.json来作为后缀,这样只要在web.xml中拦截就行了。
    
    

    其中有人问我说,为什么要用.html作为后缀名访问,如果不用它的话也不会有这样的错误出现,多省事。 其实我我觉的用.html作为后缀名访问的话,使得url形成了一种伪路径,相对来说增强了安全性。

  • 相关阅读:
    linux的openfire运行日志配置经历
    基于Html5的兼容所有主流浏览器的在线视频播放器videoJs
    Eclipse下使用Fat Jar插件对源代码进行打包
    ubuntu下的openfire安装、配置、运行
    linux系统时间同步更新
    PRD产品需求文档概要
    oracle实现自动记录存储过程、自定义函数执行错误
    Oracler读取各种格式的相关日期格式
    linux中shell变量$#,$@,$0,$1,$2的含义解释
    Linux的五个查找命令
  • 原文地址:https://www.cnblogs.com/lirenhe/p/10737498.html
Copyright © 2020-2023  润新知