zoukankan      html  css  js  c++  java
  • 使用spring mvc返回JSON,chrome可以,firefox不行的问题定位

                                          转载http://ks.netease.com/blog?id=4024  作者:李景
     
     
    场景:
             前端Post请求同一个url地址,在chrome浏览器上有正常返回json,而在firefox浏览器上却报500错误。
             下面是controller层的写法:
             
       其他类似的接口都可以正常使用,查看了其他接口的写法,区别在于多了一个header。
     
       与其他接口唯一的区别就是少写了一个Accept=application/json
     
    这是为什么呢?通过查看源码以及对两个浏览器请求头的对比,终于找出问题的原因,下面一一道来。
    看到后台有报错:
    根据错误,大概可以看出是模板解析错误,怎么用ff请求的时候会使用xml进行解析呢?
    应用是使用Freemarker进行页面渲染,配置如下:

     <bean
                >
            <property name="defaultContentType" value="application/json"/>
            <property name="mediaTypes">
                <map>
                    <entry key="html" value="text/html;charset=UTF-8"/>
                    <entry key="json" value="application/json;charset=UTF-8"/>
                    <entry key="xml" value="application/xml;charset=UTF-8"/>
                </map>
            </property>
            <property name="viewResolvers">
                <list>
                    <bean
                            >
                        <property name="cache" value="false"/>
                        <property name="prefix" value=""/>
                        <property name="suffix" value=".ftl"/>
                        <property name="exposeSpringMacroHelpers" value="true"/>
                        <property name="exposeRequestAttributes" value="true"/>
                        <property name="exposeSessionAttributes" value="true"/>
                        <property name="allowSessionOverride" value="true"/>
                        <property name="contentType" value="text/html;charset=UTF-8"/>
                    </bean>
                </list>
            </property>
            <property name="defaultViews">
                <list>
                    <bean
                            >
                        <property name="objectMapper" ref="objectMapper"/>
                        <property name="contentType" value="application/json;charset=UTF-8"/>
                        <property name="modelKeys">
                            <set>
                                <value>msg</value>
                                <value>res</value>
                                <value>errmsg</value>
                            </set>
                        </property>
                    </bean>
                    <bean id="marshallingView"
                          >
                        <property name="marshaller" ref="xstreamMarshaller"></property>
    <property name="modelKey" value="msg"></property>
                       <property name="contentType" value="application/xml"/>
                    </bean>
                </list>
            </property>
        </bean>
    Freemarker有两种默认的返回结果,分别是json和xml。
    最后返回的结果会由org.springframework.web.servlet.view.ContentNegotiatingViewResolver这个类来处理,由这个类来决定使用哪种view方式返回。
    具体的转换方法如下:
    再来看一下chrome请求头部和firefox请求头部的区别:
    chrome的请求头中Accept的值为:*/*
    对应上面的步骤:
    1、获得请求头部中accept信息:*/*

    2、获得转换器中支持Accept的media类型:*/*

    3、转换器中支持的media类型是否兼容请求过来的Accept类型:*/*

    4、根据请求等参数选择最佳的view

    配置文件件配置了defaltView为MappingJackson2JsonView和MarshallingView,顺序匹配,为*时直接匹配上第一种,直播选择MappingJackson2JsonView解析。

     

    firefox中请求头的Accept为text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    对应上面的步骤:
    1、获得请求头部中accept信息:text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8

    2、获得转换器中支持Accept的media类型:*/*

    3、转换器中支持的media类型是否兼容请求过来的Accept类型:text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8

    4、根据请求等参数选择最佳的view

    配置文件件配置了defaltView为MappingJackson2JsonView和MarshallingView,顺序匹配,当匹配到application/xml时,直播返回使用MarshallingView解析。

     

    以上步骤均是controller中没有加headers = { "Accept=application/json" }的情况,那为什么加了这段代码,firefox就可以运行了呢?

    这时对应上面的步骤结果为:

    1、获得请求头部中accept信息:text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8

    2、获得转换器中支持Accept的media类型:application/json;q=0.8

    3、转换器中支持的media类型是否兼容请求过来的Accept类型:application/json;q=0.8

    4、根据请求等参数选择最佳的view:candidateViews类型为application/json,自然用MappingJackson2JsonView解析。

     

    看上面的步骤大家已经明白了,加上Accept=application/json后获取的media类型就可以直接为application/json了,所以可以直接使用MappingJackson2JsonView解析,进而返回json数据格式。

    再做了个实验,就是调换了一下defaultVeiws的配置顺序,把MarshallingView放在前面,在不加Accept=application/json,用chrome请求时,结果返回xml格式。

    也就是说当accept是*/*时,他是顺序匹配的。

     

    在spring mvc中,如果想返回的格式是指定的,也可以配置produces变量:

    @RequestMapping(value = "/upload",produces="application/json;charset=UTF-8")

    也可以达到同样的效果。

     

    结论:

    使用spring mvc时,如果返回的数据格式不正确,需要看一下请求头部的accept、controller层的header配置、以及配置文件中模板的渲染类型和配置顺序,通过这三个方式可以定位出原因。

     

  • 相关阅读:
    Django Rest Framework(认证、权限、限制访问频率)
    MySql 三大知识点——索引、锁、事务
    django聚合查询
    Python装饰器用法
    linux上ssh免密登录原理及实现
    为github公开项目单独设置用户名
    golang协程池设计
    Django-Signals信号量
    linux tcp相关参数
    记一次性能优化,限制tcp_timewait数量,快速回收和重用
  • 原文地址:https://www.cnblogs.com/cangqiongbingchen/p/5282861.html
Copyright © 2011-2022 走看看