解決fastjson從1.1.41升級(jí)到1.2.28后報(bào)錯(cuò)問(wèn)題詳解
最近因?yàn)閒astjson安全漏洞,升級(jí)jar包時(shí),踩了一些坑。
新版本FastJsonHttpMessageConverter初始化,默認(rèn)設(shè)置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升級(jí)到1.2.28之后,請(qǐng)求報(bào)錯(cuò):
json java.lang.IllegalArgumentException: 'Content-Type' cannot contain wildcard type '*'
原因是在1.1.41中,F(xiàn)astJsonHttpMessageConverter初始化時(shí),設(shè)置了MediaType。
public FastJsonHttpMessageConverter(){ super(new MediaType("application", "json", UTF8), new MediaType("application", "*+json", UTF8)); }
而在1.2.28中,設(shè)置的MediaType為‘/',即:
public FastJsonHttpMessageConverter() { super(MediaType.ALL); // */* }
后續(xù)在org.springframework.http.converter.AbstractHttpMessageConverter.write過(guò)程中,又要判斷Content-Type不能含有通配符,這應(yīng)該是一種保護(hù)機(jī)制,并強(qiáng)制用戶自己配置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) { //設(shè)置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設(shè)置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>
新版本序列化默認(rèn)不再對(duì)字段進(jìn)行排序
這個(gè)是一個(gè)簽名算法的場(chǎng)景:客戶端對(duì)參數(shù)進(jìn)行序列化,然后md5加密成一個(gè)簽名;服務(wù)端按照相同的算法解析一遍參數(shù),對(duì)比簽名值。這里加密依賴json序列化之后的字符串,也就依賴序列化時(shí)字段的排序。
這是fastjson做了一個(gè)性能優(yōu)化,將排序需求抽象出一個(gè)SerializerFeature,供用戶自己配置。如果需要排序場(chǎng)景,在序列化時(shí)添加參數(shù)SerializerFeature.MapSortField即可,即:
JSON.toJSONString(obj, SerializerFeature.MapSortField);
官方文檔
1.2.3之后的版本,Map的序列化沒(méi)有做排序再輸出,原因是通過(guò)TreeMap排序很影響性能。
1.2.27版本中增加SerializerFeature.MapSortField實(shí)現(xiàn)同樣的功能。
使用方法如下:
a) 傳入SerializerFeature.MapSortField參數(shù)。 JSON.toJSONString(map, SerializerFeature.MapSortField);
b) 通過(guò)代碼修改全局缺省配置。 JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.MapSortField.getMask();
c) 通過(guò)JVM啟動(dòng)參數(shù)配置修改全局配置 -Dfastjson.serializerFeatures.MapSortField=true
d) 通過(guò)類路徑下的fastjson.properties來(lái)配置 fastjson.serializerFeatures.MapSortField=true
新老版本序列化和反序列化不兼容,會(huì)出亂碼。
更多關(guān)于fastjson的相關(guān)文章請(qǐng)點(diǎn)擊下面的相關(guān)鏈接
相關(guān)文章
詳解SpringBoot結(jié)合swagger2快速生成簡(jiǎn)單的接口文檔
這篇文章主要介紹了詳解SpringBoot結(jié)合swagger2快速生成簡(jiǎn)單的接口文檔,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-05-05java實(shí)現(xiàn)隊(duì)列queue數(shù)據(jù)結(jié)構(gòu)詳解
大家好,本篇文章主要講的是java實(shí)現(xiàn)隊(duì)列queue數(shù)據(jù)結(jié)構(gòu)詳解,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下2022-02-02springboot實(shí)現(xiàn)用戶名查找用戶功能
本文主要介紹了springboot實(shí)現(xiàn)用戶名查找用戶功能,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04SpringBoot獲取配置文件的簡(jiǎn)單實(shí)現(xiàn)方法
這篇文章主要給大家介紹了關(guān)于SpringBoot如何獲取配置文件的簡(jiǎn)單實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring Boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05mybatis-4 mybatis與spring結(jié)合使用及原理解析
本文通過(guò)圖文并茂的形式給大家介紹了mybatis-4 mybatis與spring結(jié)合使用及原理解析,非常不錯(cuò),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2019-04-04