简介
Feign 是一个声明式的 Web Service 客户端。它的出现使开发 Web Service 客户端变得很简单。使用 Feign 只需要创建一个接口加上对应的注解,比如:@FeignClient
注解。 Spring Cloud Open Feign 对 Feign 进行增强支持 Spring Mvc 注解,可以像 Spring Web 一样使用 HttpMessageConverters 等。
简而言之,Feign用来做服务调用,在Spring Cloud 中使用 Feign,可以更简单的使用 HTTP 请求访问远程服务。
基本使用
引入依赖
1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
启动类加入以下注解
1
2
/** 激活Feign客户端 */
@EnableFeignClients
定义一个Feign客户端
1
2
3
4
5
6
7
8
@FeignClient(name = "testAPIClient",url = "${api.url}",configuration = FeignConfiguration.class)
public interface TestAPIClient {
@RequestMapping(path = "/add",
method =RequestMethod.POST,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public String testAdd (@RequestParam("name") String name);
}
produces是注解@requestMapping注解里面的属性项,它的作用是指定返回值类型,不但可以设置返回值类型还可以设定返回值的字符编码;
consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
@FeignClient 注解
- configuration:Feign 配置类,可以自定义 Feign 的 Encoder、Decoder、LogLevel、Contract。
- name:指定 Feign Client 的名称,如果项目使用了
Ribbon
,name 属性会作为微服务的名称,用于服务发现。- url:url 一般用于调试,可以手动指定
@FeignClient
调用的地址。
测试类,调用Feign客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@RestController
@RequestMapping(
value = "/test"
)
public class TestController {
@Resource
private TestAPIClient testAPIClient;
@RequestMapping(
value = "/testFeign",
method = RequestMethod.POST
)
String testFeign(@RequestParam("name") String name) {
return testAPIClient.testAdd(ame);
}
}
踩坑记录
今天在项目中遇到了一个问题,在Feign调用时出现了异常,
feign.FeignException: status 400 reading xxx…
经过分析日志与百度,发现是参数超长了,原来的Feign客户端实现方式是这样
1
2
@RequestMapping(path = "/xxx", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
String test(@RequestParam("data") String data);
在没有改变默认Encoder的设置的情况下(没有指定@RequestMapping的consumes属性),FeignClient 对于简单类型的参数,例如String,Integer这些包装类,这种类型将被编码为form表单参数,即便写了method=RequestMethod.POST,但是参数没有出现在Body中,而是在URL上,会存在超长的情况
解决方案
引入依赖
1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form-spring</artifactId>
<version>3.4.1</version>
</dependency>
修改Feign客户端
1
2
3
4
5
6
7
@FeignClient(name = "xxx",url = "${api.url}",configuration = FeignConfiguration.class)
public interface xxx {
@RequestMapping(path = "/xxx", method = RequestMethod.POST,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
String test(Map<String,?> data);
}
- 属性
consumes = {"application/x-www-form-urlencoded"}
,指定Feign以表单方式提交- 参数使用
Map<String, ?>
形式 (不再是@RequestParam("parameter")
这种形式);
配置类,注册一个feignFormEncoder
bean
组件的方式到应用上下文。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Configuration
public class FeignConfiguration {
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
// 注意这里方法名称,也就是bean的名称是什么不重要,
// 重要的是返回类型要是 Encoder 并且实现类必须是 FormEncoder 或者其子类
// new一个form编码器,实现支持form表单提交
@Bean
@Primary
@Scope(SCOPE_PROTOTYPE)
public Encoder feignFormEncoder() {
return new SpringFormEncoder(new SpringEncoder(messageConverters));
}
//关闭Feign日志
@Bean
public Logger.Level feignLoggerLevel(){
return Logger.Level.NONE;
}
}
至此,通过接口调用就不会提示400的错误了
参考地址
感谢以下大佬的链接提供学习思路
Feign 基本使用
https://blog.csdn.net/wo18237095579/article/details/83343915
SpringCloud Feign Post表单请求
https://www.jianshu.com/p/08a5dd04093e
@EnableFeignClients 客户端详细
https://www.jianshu.com/p/62d6c4779c01
使用Feign实现Form表单提交
https://blog.csdn.net/weixin_33962923/article/details/89651126
官方指导
https://github.com/OpenFeign/feign-form
Spring Cloud : feign 客户端使用FORM形式POST数据
https://blog.csdn.net/andy_zhang2007/article/details/87860407