关于SpringMvc中HttpMessageConverter的理解

版本springboot-2.2.6

  • HttpMessageConverter在SpringMVC中的作用

在这里插入图片描述

  • 最近通过configureMessageConverters重写HttpMessageConverter时候,通过浏览器请求出现了乱码,响应头也从Content-Type :application/json 变成Content-Type: text/html下面是代码片段
 		// 字符串
        StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
        stringHttpMessageConverter.setWriteAcceptCharset(false);
        converters.add(stringHttpMessageConverter);
        // 默认JSON
        MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = mappingJackson2HttpMessageConverter();
        mappingJackson2HttpMessageConverter.setSupportedMediaTypes(new LinkedList<MediaType>(){{
            add(MediaType.APPLICATION_JSON);
        }});
        converters.add(new StringHttpMessageConverter());
        ObjectMapper objectMapper = new ObjectMapper();
        ObjectMapperUtil.setObjectMapper(objectMapper);
        mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
        converters.add(0, mappingJackson2HttpMessageConverter);
        //fastJson
        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
        converters.add(fastJsonHttpMessageConverter);

在这里插入图片描述
在这里插入图片描述

  • 通过分析找到源码,消息出口的convert方法writeWithMessageConverters,发现spring的响应式根据请求的accept来匹配相应的content-type类型的,下面是我本次请求的accept

  • 在这里插入图片描述

  • 接下来奇怪的事情发生了
    在这里插入图片描述

  • 我明明只配置了一个content-type=application/json类型,发现却有一个全匹配类型content-type=/

  • 导致所有的accept类型都被添加到了List mediaTypesToUse = new ArrayList(); 这个可使用的数组里,在迭代mediaTypesToUse时,随即取出了其中的第一个类型text/html,并且这个text/html,是没有charset编码的,所以导致了乱码在这里插入图片描述

  • 那么为什么会出现*/*嘛,继续往下走
    在这里插入图片描述

  • 这段代码我们可以看出,有三个自定义的消息处理器,分别支持application/json,text/plain,/,由于Stirng的消息处理器,相应类型就被排除了,代码如下

    protected List<MediaType> getProducibleMediaTypes(HttpServletRequest request, Class<?> valueClass, @Nullable Type targetType) {
        Set<MediaType> mediaTypes = (Set)request.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
        if (!CollectionUtils.isEmpty(mediaTypes)) {
            return new ArrayList(mediaTypes);
        } else if (this.allSupportedMediaTypes.isEmpty()) {
            return Collections.singletonList(MediaType.ALL);
        } else {
            List<MediaType> result = new ArrayList();
            Iterator var6 = this.messageConverters.iterator();

            while(true) {
                while(var6.hasNext()) {
                    HttpMessageConverter<?> converter = (HttpMessageConverter)var6.next();
                    if (converter instanceof GenericHttpMessageConverter && targetType != null) {
                        if (((GenericHttpMessageConverter)converter).canWrite(targetType, valueClass, (MediaType)null)) {
                            result.addAll(converter.getSupportedMediaTypes());
                        }
                    } else if (converter.canWrite(valueClass, (MediaType)null)) {
                        result.addAll(converter.getSupportedMediaTypes());
                    }
                }

                return result;
            }
        }
    }
  • 这段是获取支持的media-type类型,如果Converter能够write就算支持,很显然text/plain不能写json类型,默认支持所有类型

  • 因此只有FastJsonHttpMessageConverter这个转换器,由于没有配置任何的media-type,默认设置MediaType.ALL

    public FastJsonHttpMessageConverter() {
        super(MediaType.ALL);
    }

  • 在与accept匹配时,如果converter支持所有类型,那么优先权在于Accept,否则尽可能匹配并使用converter支持类型

解决方案

  • 1、给fastJsonHttpMessageConverter设置支持类型,
  • fastJsonHttpMessageConverter.setSupportedMediaTypes(new LinkedList<MediaType>(){{ add(MediaType.APPLICATION_JSON); }});
  • 但这样违背了初衷,这样就不能解析text类型转json,fastJson可以接收text的json类型,可以默认下划线转驼峰等,比如我下面这个请求
    在这里插入图片描述
  • 在AbstractMessageConverterMethodArgumentResolver消息解析时,便使用到了fastJsonHttpMessageConverter
    在这里插入图片描述

结论

  • 可以通过配置 add(MediaType.valueOf(“text/html;charset=UTF-8”)),使其满足accept的匹配要求,accept便会使用MediaType
        mappingJackson2HttpMessageConverter.setSupportedMediaTypes(new LinkedList<MediaType>(){{
            add(MediaType.APPLICATION_JSON);
            add(MediaType.valueOf("text/html;charset=UTF-8"));
        }});
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值