实践--问题定位:FeignException$UnsupportedMediaType: [415 ]

背景:

SpringCloud 引入 feign-okhttp 之后,web接口与feign接口的content-type不同导致问题:FeignException$UnsupportedMediaType: [415 ]

问题定位过程:

根据报错异常栈打印的信息,定位到SynchronousMehthodHandler.java第156行:

response里面的状态码已经是415了,Unsupported Media Type,向上找到发出request的地方:

debug进去,找到OkHttp的具体实现:

debug到底168行,发现input(其实也是个request)的content-type有两个值:applicaiton/json,x-www-form-urlencoded。(其中application/json是因为我所调用的feign接口的参数被@RequestBody修饰,所以生成的input的content-type是applicaiton/json;而 x-www-form-urlencoded是因为我的web接口定义的参数被@RequestParam修饰,所以发过来的web请求的content-type需要是x-www-form-urlencoded),到这里有些疑问,为什么content-type会有两个值呢???不过我们先debug进第168行,看看如何进行了request转变,因为这个转变之后的request就是最终发出去的request了:

 59到68行,把input里面的content-type都加入到了用于构建新的request的requestBuilder里面对应的content-type中,然后对mediaType进行了赋值,因为x-www-form-urlencoded在后,所以最终mediaType的值为x-www-form-urlencoded。

74到85行,进行了判断,如果input的方法为POST、PUT、PATCH,那么就把requestBuilder中的content-type给清空了!为什么要把content-type给清空,415肯定和这里有关系!!!

然后看到最终返回的利用requestBuilder构造出来的request的body里面的mediaType是x-www-form-urlencoded,而我定义的feign接口的参数其实是被@RequestBody所修饰的!!!

如果不清空content-type是不是就好了,但是源码也改不了啊;

那如果把input里面的content-type的两个值:application/json,x-www-form-urlencoded换一下顺序,那mediaType的最终赋值不就是applicaiton/json了么。。。但好像也不好实现。

唉,为什么这里的content-type会有两个值呢?很奇怪,于是一步一步返回,看看这两个content-type是怎么来的:

又回到了SynchronousMethodHandler中的executeAndDecode方法中,在这里看到传入的template(大概也是为构造request的一个类)里面的content-type有一个值:applicaiton/json(通过所要调用的feign接口的方法定义中的参数被@RequestBody修饰所生成的),但是经过targetRequest(template)之后,request中的content-type就变成了两个值。于是debug进去第101行:

哦,这里有interceptor(拦截器),真相应该在interceptor的代码中,我这里debug的时候,看到一个interceptor。继续debug:

 这里在第26行,获取当了当前所在requestContext中的request,就是获取到了你当前的web请求:request,而传入的requestTemplate其实会在接下来的代码中去构造我们的feign请求。在27行到34行做的一件事:将request里面除content-length的其他请求头的值加入的requestTemplate中对应的请求头里,而且通过debug发现:确实是把web请求的content-type:x-www-form-urlencoded加入到了feign请求的content-type中,于是feign请求的content-type就有了两个值:application/json,x-www-form-urlencoded,而且x-www-form-urlencoded在后。所以在后面的OkHttpClient.toOkHttpRequest(input)方法中导致最后的mediaType等于了x-www-form-urlencoded。

到这里,问题找到了,就是这个interceptor处理不当导致的,解决方法很简单,就是再加一个if,把content-type字段排除在外:web请求的content-type不应该影响到feign请求。但这个interceptor整体还是有用的,可以把web请求中的token、user-agent、host等其他字段传递给feign请求。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值