FastJsonHttpMessageConverter请求中参数序列化问题排查
问题
前几天帮忙其他部门的多个祖先级项目改造开发,服务间使用Feign方式调用,发现接口提供方接收到的请求,没有请求参数,经过排查发现服务调用方的FastJsonHttpMessageConverter配置方式存在问题,导致请求中RequestBody的序列化出现问题。
排查步骤
- 服务提供方排查
经debug DispatcherServlet发现request中各请求参数名发生了变化—命名规则由camel变成了snake_case(蛇形命名规则),接口的请求参数名的命名规则是camel,所以导致接口中各个参数没有值,判定很有可能是请求调用方的HttpMessageConverter的配置有问题;
- 服务调用方排查
debug查发出请求时请求的所有的messageConverter,发现项目里添加了FastJsonHttpMessageConverter,在经过FastJsonHttpMessageConverter 对请求参数的处理后,HttpOutputMessage输出的请求参数名发生了变化—把原来camel规则的请求参数统一进行了snake_case转换;
- 至此基本定位问题原因-FastJsonHttpMessageConverter的配置导致参数命名发生改变,进而导致服务提供方接收不到原有的参数。
解决方法
深入阅读FastJsonHttpMessageConverter源码,在writeInternal 和 readInternal时,会使用FastJsonConfig-> SerializeConfig,来进行请求体的序列化和反序列化,如图-1

图-1
方法一:
- 自定义FeignClient的configuration覆盖默认的FeignClientsConfiguration,在自定义的FeignConfiguration中去重新定义SpringEncoder和SpringDecoder,在Encoder和Decoder中去重新配置FastJsonHttpMessageConverter;
- 针对此FeignClient的configuration定义一个此feign实例的FastJsonConfig->SerializeConfig,而非使用全局的SerializeConfig(之所以不用全局,因为项目比较庞杂,怕影响其他三方服务调用),设置其propertyNameStrategy = CamelCase
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import feign.Logger.Level;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.codec.ErrorDecoder;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.cloud.netflix.feign.support.ResponseEntityDecoder;
import org.springframework.cloud.netflix.feign.support.SpringDecoder;
import org.springframework.cloud.netflix.feign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter; public class FeignConfiguration {
HttpMessageConverters converters;
ObjectFactory<HttpMessageConverters> httpMessageConverters; public FeignConfiguration() {
} @PostConstruct
public void init() {
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
List<MediaType> supportedMediaTypes = new ArrayList();
supportedMediaTypes.add(MediaType.APPLICATION_JSON);
supportedMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
supportedMediaTypes.add(MediaType.APPLICATION_ATOM_XML);
supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
supportedMediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
supportedMediaTypes.add(MediaType.APPLICATION_PDF);
supportedMediaTypes.add(MediaType.APPLICATION_RSS_XML);
supportedMediaTypes.add(MediaType.APPLICATION_XHTML_XML);
supportedMediaTypes.add(MediaType.APPLICATION_XML);
supportedMediaTypes.add(MediaType.IMAGE_GIF);
supportedMediaTypes.add(MediaType.IMAGE_JPEG);
supportedMediaTypes.add(MediaType.IMAGE_PNG);
supportedMediaTypes.add(MediaType.TEXT_EVENT_STREAM);
supportedMediaTypes.add(MediaType.TEXT_HTML);
supportedMediaTypes.add(MediaType.TEXT_MARKDOWN);
supportedMediaTypes.add(MediaType.TEXT_PLAIN);
supportedMediaTypes.add(MediaType.TEXT_XML);
converter.setSupportedMediaTypes(supportedMediaTypes);
this.converters = new HttpMessageConverters(new HttpMessageConverter[]{converter});
this.httpMessageConverters = () -> {
return this.converters;
};
} @Bean
public Level feignLoggerLevel() {
return Level.FULL;
} @Bean
public ErrorDecoder businessErrorDecoder() {
return new FeignErrorDecoder();
} @Bean
public Decoder feignDecoder() {
return new ResponseEntityDecoder(new SpringDecoder(this.httpMessageConverters));
} @Bean
public Encoder feignEncoder() {
return new SpringEncoder(this.httpMessageConverters);
} }
方法二:
服务提供方,feign接口的@RequestBody 对应的请求实体类添加@JSONType(naming=PropertyNamingStrategy.CamelCase)
SerializeConfig在getWriter时会读取这个注解来决定序列化/反序列化时的请求体中参数的命名规则。

1 import com.alibaba.fastjson.PropertyNamingStrategy;
2 import com.alibaba.fastjson.annotation.JSONType;
3
4 import java.io.Serializable;
5
6 /**
7 * @author zhaoxinbo
8 * @name: UserRequest
9 * @description: 请求参数-user RequestBody
10 * @date 2021/9/24 20:22
11 */
12 @JSONType(naming = PropertyNamingStrategy.CamelCase)
13 public class UserRequest implements Serializable {
14 private Long userId;
15
16 private String userName;
17
18 public Long getUserId() {
19 return userId;
20 }
21
22 public void setUserId(Long userId) {
23 this.userId = userId;
24 }
25
26 public String getUserName() {
27 return userName;
28 }
29
30 public void setUserName(String userName) {
31 this.userName = userName;
32 }
33 }
建议使用第二种方式,服务提供方明确告知请求参数的命名规则,当然第一种方法中如果有服务提供方来提供FeignConfiguration的话更方便。
FastJsonHttpMessageConverter请求中参数序列化问题排查的更多相关文章
- axio 请求中参数是数组
前言 最近在做 Vue 项目中,Get 请求中有的参数是数组,传 JSON 字符串是没有问题的,但是直接传数组就一直报错,有问题. 参数后面无故加了 [],例如:UserIds 变成 UserIds[ ...
- ajax 之POST请求,参数序列化
比如,,我们在没有使用jquery的时候,没有$.post来让我们使用,那我们像下面这样直接发送: var params1 = { username: username, passwrod: pass ...
- 解决backbone url请求中参数有中文,存入数据库是乱码
最近项目用到了backbone 做前后端的分离方案,遇见了中文乱码问题,解决方案总结如下: 假设需要存一条课程记录到后台 model定义如下: var AddCourse= Backbone.Mo ...
- PHP中get请求中参数的key不能是para
¶会被转化成¶,然后就无法进行下去了. 仅作记录.
- Spring MVC如何获取请求中的参数
目录 一.获取URL中路径参数 1.1 @PathVariable 注解 1.2 @PathParam 注解 二.获取请求参数: 2.1 GET请求 2.1.1 获取请求中的单个参数:@Request ...
- http请求中的中文乱码问题
通过浏览器访问服务器页面和资源时,不可避免地要传送中文字串,如果客户机与服务器不能用同一码表解析字串,肯定会出现各种各样的乱码问题.我总结了几个乱码场景及解决办法,如下 1.服务器上的中文字串被客户端 ...
- AJAX请求 $.ajaxSetup方法的使用:设置AJAX请求的默认参数选项,当程序中需要发起多个AJAX请求时,则不用再为每一个请求配置请求的参数
定义和用法ajaxSetup() 方法为将来的 AJAX 请求设置默认值.语法$.ajaxSetup({name:value, name:value, ... }) 该参数为带有一个或多个名称/值对的 ...
- (三)Asp.net web api中的坑-【http post请求中的参数】
接上篇, HttpPost 请求 1.post请求,单参数 前端 var url = 'api/EnterOrExit/GetData2';var para = {};para["Phone ...
- post请求中的参数形式和form-data提交数据时取不到的问题
@Controller页面form表单请求时不会丢数据返回json数据时需要加 注解@ResponseBody请求格式如下 @ResponseBody public Object login(Sign ...
随机推荐
- selenium定位元素方法汇总
#打开网页前三步 from selenium import webdriver driver=webidriver.Chrome() driver.get("https://www.baid ...
- Abp Vnext Blazor替换UI组件 集成BootstrapBlazor(详细过程)
Abp Vnext自带的blazor项目使用的是 Blazorise,但是试用后发现不支持多标签.于是想替换为BootstrapBlazor. 过程比较复杂,本人已经把模块写好了只需要替换掉即可. 点 ...
- Codeforces 1067D - Computer Game(矩阵快速幂+斜率优化)
Codeforces 题面传送门 & 洛谷题面传送门 好题. 首先显然我们如果在某一次游戏中升级,那么在接下来的游戏中我们一定会一直打 \(b_jp_j\) 最大的游戏 \(j\),因为这样得 ...
- HDFS06 DataNode
DataNode 目录 DataNode DataNode工作机制 数据完整性 DataNode掉线时限参数设置 DataNode工作机制 一个数据块在DataNode上以文字形式存储在磁盘上,包括一 ...
- acquaint
Interpersonal relationships are dynamic systems that change continuously during their existence. Lik ...
- day02 MySQL基本操作
day02 MySQL基本操作 昨日内容回顾 数据库演变史 1.纯文件阶段 2.目录规范 3.单机游戏 4.联网游戏 # 数据库就是一款帮助我们管理数据的程序 软件开发架构及数据库本质 cs架构与bs ...
- day10设置文件权限
day10设置文件权限 yum复习 1.修改IP [root@localhost ~]# sed -i 's#.200#.50#g' /etc/sysconfig/network-scripts/if ...
- Django url中可以使用类视图.as_view()进行映射的原因
说明:在练习天天生鲜项目时,对利用类视图去与正则匹配到的url做映射有点疑惑,经过查看他人博客以及自我分析算是整明白了,所以记录一下 参考:https://www.zmrenwu.com/post/5 ...
- celery开启worker报错django.core.exceptions.ImproperlyConfigured: Requested setting INSTALLED_APPS, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE o
其实挺简单的问题,但花了自己一个下午来解决,先是浏览各种博客,无果:没办法,然后去看celery官方文档,无果,近乎绝望,最后仔细看代码,找到问题所在(如下),自学狗这效率...... 下面是自己ta ...
- SpringCloud微服务实战——搭建企业级开发框架(三十二):代码生成器使用配置说明
一.新建数据源配置 因考虑到多数据源问题,代码生成器作为一个通用的模块,后续可能会为其他工程生成代码,所以,这里不直接读取系统工程配置的数据源,而是让用户自己维护. 参数说明 数据源名称:用于查找区分 ...