解决fastjson从1.1.41升级到1.2.28后报错问题详解

作者:漫夭 时间:2021-12-30 21:55:35 

最近因为fastjson安全漏洞,升级jar包时,踩了一些坑。

新版本FastJsonHttpMessageConverter初始化,默认设置MediaType为*/*

背景:

使用Spring RestTemplate,配置如下:


 <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
   <constructor-arg ref="ky.clientHttpRequestFactory"/>
   <property name="errorHandler">
     <bean class="org.springframework.web.client.DefaultResponseErrorHandler"/>
   </property>
   <property name="messageConverters">
     <list>
       <bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
       <bean class="cn.com.autodx.common.jsonView.ViewAwareJsonMessageConverter">
       </bean>
       <bean class="org.springframework.http.converter.StringHttpMessageConverter">
         <property name="supportedMediaTypes">
           <list>
             <value>text/html;charset=UTF-8</value>
             <value>application/json</value>
             <value>text/javascript;charset=utf-8</value>
           </list>
         </property>
       </bean>
     </list>
   </property>
 </bean>

其中ViewAwareJsonMessageConverter继承自FastJsonHttpMessageConverter。

fastjson从1.1.41升级到1.2.28之后,请求报错:


json java.lang.IllegalArgumentException: 'Content-Type' cannot contain wildcard type '*'

原因是在1.1.41中,FastJsonHttpMessageConverter初始化时,设置了MediaType。


 public FastJsonHttpMessageConverter(){
   super(new MediaType("application", "json", UTF8), new MediaType("application", "*+json", UTF8));
 }

而在1.2.28中,设置的MediaType为‘/',即:


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

后续在org.springframework.http.converter.AbstractHttpMessageConverter.write过程中,又要判断Content-Type不能含有通配符,这应该是一种保护机制,并强制用户自己配置MediaType。代码如下:


 @Override
 public final void write(final T t, MediaType contentType, HttpOutputMessage outputMessage)
     throws IOException, HttpMessageNotWritableException {
   final HttpHeaders headers = outputMessage.getHeaders();
   if (headers.getContentType() == null) {
     MediaType contentTypeToUse = contentType;
     if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) {
       contentTypeToUse = getDefaultContentType(t);
     }
     if (contentTypeToUse != null) {
     //设置Content-Type,不允许含有通配符
       headers.setContentType(contentTypeToUse);
     }
   }
   ......
   if (outputMessage instanceof StreamingHttpOutputMessage) {
     ......
   }else {
   //自定义MessageConverter的write操作
     writeInternal(t, outputMessage);
     outputMessage.getBody().flush();
   }
 }
 public void setContentType(MediaType mediaType) {
   Assert.isTrue(!mediaType.isWildcardType(), "'Content-Type' cannot contain wildcard type '*'");
   Assert.isTrue(!mediaType.isWildcardSubtype(), "'Content-Type' cannot contain wildcard subtype '*'");
   set(CONTENT_TYPE, mediaType.toString());
 }

所以,需要为ViewAwareJsonMessageConverter设置supportedMediaTypes:


<bean class="cn.com.autodx.common.jsonView.ViewAwareJsonMessageConverter">
 <property name="supportedMediaTypes">
   <list>
     <value>application/json;charset=UTF-8</value>
     <value>application/*+json;charset=UTF-8</value>
   </list>
 </property>
</bean>

新版本序列化默认不再对字段进行排序

这个是一个签名算法的场景:客户端对参数进行序列化,然后md5加密成一个签名;服务端按照相同的算法解析一遍参数,对比签名值。这里加密依赖json序列化之后的字符串,也就依赖序列化时字段的排序。

这是fastjson做了一个性能优化,将排序需求抽象出一个SerializerFeature,供用户自己配置。如果需要排序场景,在序列化时添加参数SerializerFeature.MapSortField即可,即:


JSON.toJSONString(obj, SerializerFeature.MapSortField);

官方文档

1.2.3之后的版本,Map的序列化没有做排序再输出,原因是通过TreeMap排序很影响性能。

1.2.27版本中增加SerializerFeature.MapSortField实现同样的功能。

使用方法如下:

a) 传入SerializerFeature.MapSortField参数。 JSON.toJSONString(map, SerializerFeature.MapSortField);

b) 通过代码修改全局缺省配置。 JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.MapSortField.getMask();

c) 通过JVM启动参数配置修改全局配置 -Dfastjson.serializerFeatures.MapSortField=true

d) 通过类路径下的fastjson.properties来配置 fastjson.serializerFeatures.MapSortField=true

新老版本序列化和反序列化不兼容,会出乱码。

来源:https://www.cnblogs.com/shoren/p/fastjson.html

标签:fastjson
0
投稿

猜你喜欢

  • Flutter刷新组件RefreshIndicator自定义样式demo

    2023-07-06 15:56:45
  • java信号量控制线程打印顺序的示例分享

    2023-05-09 12:27:38
  • Hadoop组件简介

    2023-08-20 14:07:00
  • Java线程之守护线程(Daemon)用法实例

    2023-11-29 09:15:13
  • java 中遍历取值异常(Hashtable Enumerator)解决办法

    2023-08-06 05:17:08
  • JAVA JVM面试题总结

    2021-07-12 04:55:13
  • 基于Java数组实现循环队列的两种方法小结

    2023-06-30 16:09:01
  • SpringBoot中dubbo+zookeeper实现分布式开发的应用详解

    2023-09-13 19:04:45
  • java对接支付宝支付接口开发详细步骤

    2023-11-16 21:31:11
  • Flutter添加页面过渡动画实现步骤

    2023-08-20 09:06:20
  • Java SpringSecurity+JWT实现登录认证

    2022-12-13 16:44:18
  • 使用Feign传递请求头信息(Finchley版本)

    2023-06-07 22:38:07
  • java开发微信分享接口的步骤

    2021-08-22 12:30:59
  • C# 多线程更新界面的错误的解决方法

    2022-01-20 15:52:21
  • java使用dom4j操作xml示例代码

    2022-03-21 18:28:38
  • Java数组越界问题实例解析

    2023-10-25 18:16:23
  • Spring Cloud Hystrix 服务降级限流策略详解

    2022-05-02 15:20:27
  • Java基础知识之Java语言概述

    2023-11-28 04:36:35
  • Android 通过SQLite数据库实现数据存储管理

    2023-09-28 11:31:59
  • Java转JSON串的几种方式

    2023-08-24 07:38:47
  • asp之家 软件编程 m.aspxhome.com