Feign发送Get请求时,采用POJO对象传递参数的最终解决方案 Request method 'POST' not supported (附带其余好几个坑)

时间:2023-02-07 19:31:16

yml:

feign:
httpclient:
enabled: true

properties:

#feign
feign.httpclient.enabled=true
        <!-- https://mvnrepository.com/artifact/io.github.openfeign/feign-httpclient -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>10.2.3</version>
</dependency>

https://blog.csdn.net/u010277958/article/details/88730889

相关阅读
【小家java】java5新特性(简述十大新特性) 重要一跃
【小家java】java6新特性(简述十大新特性) 鸡肋升级
【小家java】java7新特性(简述八大新特性) 不温不火
【小家java】java8新特性(简述十大新特性) 饱受赞誉
【小家java】java9新特性(简述十大新特性) 褒贬不一
【小家java】java10新特性(简述十大新特性) 小步迭代
【小家java】java11新特性(简述八大新特性) 首个重磅LTS版本

每篇一句
如果你真的觉得很难,那你就放弃。但是你放弃了你就不要抱怨说,我为什么没有得到

前言
spring cloud技术栈里面,Feign可以使得我们的rest调用和调用本地方法一样方便。但是它真的有非常多的坑,苦不堪言啊。本文将描述我们最为常遇到的坑:

Feign发送Get请求时,采用POJO传递参数 Request method ‘POST’ not supported

坑 例举
Feign发送Get请求时,采用POJO传递参数的坑
在使用Feign client来调用Get请求接口时,如果方法的参数是一个对象,例如:

@FeignClient("microservice-provider-user")
public interface UserFeignClient { @RequestMapping(value = "/user", method = RequestMethod.GET)
public PageBean<User> get(User user); }

我们想得好好的。分页查询,查询条件用POJO的User对象进行包装进去。但奈何:在调试的时候你会一脸懵逼,因为报了如下错误:

feign.FeignException: status 405 reading UserFeignClient#get0(User); content:
{"timestamp":1482676142940,"status":405,"error":"Method Not Allowed", "exception":"org.springframework.web.HttpRequestMethodNotSupportedException","message":"Request method 'POST' not supported","path":"/user"}

what?老夫明明用的get请求啊,你竟然说Post方法不支持?

其实这个问题,在feign的github社区里面,一直有人提出了issue,只是一直没有被解决而已。

github上相关issue参考:

希望Feign能够支持参数请求使用POJO:https://github.com/spring-cloud/spring-cloud-netflix/issues/1253
解决办法:http://www.itmuch.com/spring-cloud-sum/feign-multiple-params/
建议使用Feign原生的注解的Issue:https://github.com/spring-cloud/spring-cloud-netflix/issues/659
建议增强Feign的功能:https://github.com/spring-cloud/spring-cloud-netflix/issues/1360
建议支持可选的Request Body(目前Feign当POST一个null时,会报异常):https://github.com/spring-cloud/spring-cloud-netflix/issues/1047
虽然可以采用@RequestParam的方式解决问题,但是很恼火的我,仔细想想:

你想写一堆长长的参数吗?用一个不知道里边有什么鬼的Map吗?或者转换为post?这似乎与REST风格不太搭,会浪费url资源,我们还需要在url定义上来区分Get或者Post。

于是就开始逐行调试,知道我从feign的源码中发现了这个:

private synchronized OutputStream getOutputStream0() throws IOException {
try {
if(!this.doOutput) {
throw new ProtocolException("cannot write to a URLConnection if doOutput=false - call setDoOutput(true)");
} else {
if(this.method.equals("GET")) {
this.method = "POST";
}

这段代码是在 HttpURLConnection 中发现的,jdk原生的http连接请求工具类,原来是因为Feign默认使用的连接工具实现类,所以里面发现只要你有body体对象,就会强制的把get请求转换成POST请求。

终上所述,这也不能怪feign,是HttpURLConnection 的问题。所以接下来我准备换一个HttpClient试试,因此本利我采用apache的HttpClient。但是一定,一定需要加入如下几个步骤:

加入feign的配置项:feign.httpclient,enabled = true
在依赖中引入apache的httpclient

<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>

配置上此依赖(此依赖不可少 否则不生效的)
<!-- 使用Apache HttpClient替换Feign原生httpclient -->

<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>${feign-httpclient}</version>
</dependency>

按照上面3个步骤添加好依赖后,我们可以很*的使用User对象来传递get请求的参数了,是不是很优雅有木有。

但是一波三折,我发现服务端接受到的值都是null。因此我只能这么搞了

@FeignClient("microservice-provider-user")
public interface UserFeignClient { @RequestMapping(value = "/user", method = RequestMethod.GET)
public PageBean<User> get(@RequestBody User user); }

竟然在get请求里加上这么一个注解。结果,好使了。哈哈,完美

Feign 传参问题及传输Date类型参数的时差 坑
feign的调用如下:

List<LeftSeatCountOfDaysResp> getLeftSeatCountOfDays(
@RequestParam("configType") Integer configType,
@RequestParam("courseId") Long courseId,
@RequestParam("startDateFrom") Date startDateFrom,
@RequestParam("startDateTo") Date startDateTo,
@RequestParam("level") Integer level);

我们采用了两个date类型的参数传参,结果:
我们传入的时间为:

但服务端接受到的时间为:

天啊撸,竟然出现了我们并不熟悉的14h时差,并不是我们熟悉的8个小时。feign真是天坑啊。这是SpringCloud Feign传Date类型参数的时差导致的。

备注:使用date类型传参,如果是body里面用对象传,是不会出现时差问题的。

下面说说两种解决方案:

当发送时间类型时,直接用String发送(推荐)
Feign客户端实现FeignFormatterRegistrar接口自定义DateFormatRegister

@Component
public class DateFormatRegister implements FeignFormatterRegistrar{ public DateFormatRegister(){
} @Override
public void registerFormatters(FormatterRegistry registry) {
registry.addConverter(Date.class, String.class, new Date2StringConverter());
} private class Date2StringConverter implements Converter<Date,String>{ @Override
public String convert(Date source) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(source);
} }
}

服务端实现:

@Configuration
public class WebConfigBeans {
@Autowired
private RequestMappingHandlerAdapter handlerAdapter; /**
* 增加字符串转日期的功能
*/
@PostConstruct
public void initEditableValidation() {
ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) handlerAdapter
.getWebBindingInitializer();
if (initializer.getConversionService() != null) {
GenericConversionService genericConversionService = (GenericConversionService) initializer
.getConversionService();
genericConversionService.addConverter(String.class, Date.class, new String2DateConverter());
}
}
}

第二种比较麻烦,但是一劳永逸,代码的优雅性比第一种好。但个人而言,还是推荐使用第一种。

Feign 传参时候使用@DateTimeFormat注解 坑

@NotNull
@MyFuture
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date appointDate; //预定的预成班日期

比如这个字段,服务端上面用了@DateTimeFormat注解,这样的话,springMVC手机支持直接传字符串2018-03-03自动转换的。但是,但是,如果你是用client调用,那就不报错啦,报错啦。所以使用的时候,一定要注意啊,一定要注意啊。

总结:
虽然fiegn有很多坑,但咱不能说feign不好用。毕竟他比restTemplate或者httpClient还是优雅很多的,能够简化很多东西,负载均衡也做得不错,毕竟在本地就可以做。
---------------------
作者:_YourBatman
来源:CSDN
原文:https://blog.csdn.net/f641385712/article/details/82431502
版权声明:本文为博主原创文章,转载请附上博文链接!

Feign发送Get请求时,采用POJO对象传递参数的最终解决方案 Request method 'POST' not supported (附带其余好几个坑)的更多相关文章

  1. feign发送get请求时用复杂类传参

    如题,网上都有做法,只有有些人说的不清楚.而我自己也遇到了其他坑这里记录一下 1.就是网上说的做法: 客户端:application.yml加上配置: feign: httpclient: enabl ...

  2. spring cloud——feign为GET请求时的对象参数传递

    一.问题重现 楼主在使用feign进行声明式服务调用的时候发现,当GET请求为多参数时,为方便改用DTO对象进行参数传递.但是,在接口调用时feign会抛出一个405的请求方式错误: {"t ...

  3. 使用Feign发送HTTP请求

    使用Feign发送HTTP请求 在往常的 HTTP 调用中,一直都是使用的官方提供的 RestTemplate 来进行远程调用,该调用方式将组装代码冗余到正常业务代码中,不够优雅,因此在接触到 Fei ...

  4. IE内核发送ajax请求时不会将url中的参数编码

    有一次用户遇到创建文件,名称为中文时乱码的问题. 经调查,发现用户使用的是国产浏览器ie模式 抓取请求发现 IE: 键 值请求 POST /Handlers/CreateTxtFile.ashx?fi ...

  5. python发送requests请求时,使用登录的token值,作为下一个接口的请求头信息

    背景介绍: 发送搜索请求时,需要用到登录接口返回值中的token值 代码实现: 登录代码: 搜索接口:

  6. Python发送http请求时遇到问题总结

    1.报错信息为“ERROR 'str' object has no attribute 'endwith'”,排查发现endswith方法名写错了,少了s,写成了 'endwith' if inter ...

  7. Angular13 Angular2发送PUT请求在后台接收不到参数

    1 问题描述 利用angular2发送PUT请求时,后端接收不到参数 2 问题诊断 前段参数格式问题,后端获取参数的方法不对 3 解决问题 angular前段:将所有参数编程JSON字符串形式 spr ...

  8. SpringMVC中使用Ajax POST请求以json格式传递参数服务端通过request&period;getParameter&lpar;&quot&semi;name&quot&semi;&rpar;无法获取参数值问题分析

    SpringMVC中使用Ajax POST请求以json格式传递参数服务端通过request.getParameter("name")无法获取参数值问题分析 一:问题demo展示 ...

  9. 【Feign调用异常】org&period;springframework&period;web&period;HttpRequestMethodNotSupportedException&colon; Request method &&num;39&semi;GET&&num;39&semi; not supported

    一.异常场景描述 明明是post请求,为啥到达服务器后就变成了get请求 2019-05-30 18:07:17.055 [http-nio-10650-exec-4] ERROR c.x.xcaut ...

随机推荐

  1. Python&colon;如何删除文件中的空白行?

    def delblankline(infile,outfile): infopen = open(infile,'r') outfopen = open(outfile,'w') lines = in ...

  2. 如何使用&period;NET开发全版本支持的Outlook插件产品(一)——准备工作

    这半年一直在做Outlook的插件,因为不会VC++,所以想找一款基于.NET,用C#开发Outlook插件的技术方案.没想到,光技术选型这件事,就用各种技术手段验证了将近一个月,还花费了大量的精力做 ...

  3. 总结Unity IOC容器通过配置实现类型映射的几种基本使用方法

    网上关于Unity IOC容器使用的方法已很多,但未能做一个总结,故我这里总结一下,方便大家选择. 首先讲一下通过代码来进行类型映射,很简单,代码如下: unityContainer = new Un ...

  4. &lbrack;BZOJ1232&rsqb;&lbrack;&lbrack;Usaco2008Nov&rsqb;安慰奶牛cheer&lpar;MST&rpar;

    题目:http://hzwer.com/2493.html 分析:对于每条边,贡献的价值是这条边的边权加上这条边连接的两点的权值,所以可以把每条边的边权加上两顶点的点权作为新的边权,然后跑个最小生成树 ...

  5. JavaBean简单示例

    本示例说明: 从Login.jsp中输入用户名和密码,提交,在NewFile.jsp中显示信息. ----- 类要放在一个包中!!! UserB 类文件 package model; public c ...

  6. Kakfa揭秘 Day7 Producer源码解密

    Kakfa揭秘 Day7 Producer源码解密 今天我们来研究下Producer.Producer的主要作用就是向Kafka的brokers发送数据.从思考角度,为了简化思考过程,可以简化为一个单 ...

  7. POJ 2263 Heavy Cargo(Floyd &plus; map)

    Heavy Cargo Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3768   Accepted: 2013 Descr ...

  8. hdu4675 GCD of Sequence

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4675 题意: 给定一个长度为n的序列a,且 1<=a[i]<=m,求分别有多少个序列b,使 ...

  9. 模型组合&lpar;Model Combining&rpar;之Boosting与Gradient Boosting

    版权声明: 本文由LeftNotEasy发布于http://leftnoteasy.cnblogs.com, 本文可以被全部的转载或者部分使用,但请注明出处,如果有问题,请联系wheeleast@gm ...

  10. git &gt&semi; 2&period;3 实现同步盘的功能

    话不多说,简单粗暴 http://*.com/questions/35643201/how-to-set-up-a-sychronous-directory-in-remote ...