OpenFeign组件

什么是 OpenFeign ?

OpenFeign 是一个声明式的 HTTP 客户端,它使得我们可以非常方便地调用 HTTP 接口。OpenFeign 是 Netflix 开源的 Feign 项目的扩展,旨在与 Spring Cloud 紧密集成。它通过注解来定义接口,类似于 Spring MVC 的控制器,使得开发者可以专注于业务逻辑,而不需要关注 HTTP 请求的具体实现。

OpenFeign 使用

  1. 添加OpenFeign依赖
1
2
3
4
5
6
7
8
9
10
11
<!-- OpenFeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

<!-- 负载均衡 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

TIP : OpenFeign 通常和 loadbalancer 接口负载均衡组件搭配使用。

  1. 声明 FeignClient 客户端接口
1
2
3
4
5
6
7
8
9
@FeignClient(name = ApiConstants.SERVICE_NAME)
public interface FileFeignApi {

String PREFIX = "/file";

@PostMapping(value = PREFIX + "/test")
Response<?> test();

}

注:

  • @FeignClient 是用来标记这个接口是一个 Feign 客户端的注解。
    • name = ApiConstants.SERVICE_NAME 指定了这个 Feign 客户端所调用的服务名称。这个名称通常是在注册中心(如 Eureka 或 Nacos)中注册的服务名称。
  • String PREFIX = "/file" : 定义了一个前缀常量,用于接口中 URI 的路径前缀。
  • @PostMapping 注解标记这个方法将执行一个 HTTP POST 请求。
    • value = PREFIX + "/test" 指定了这个 POST 请求的路径,这里是 "/file/test"

2.1 创建 ApiConstants 常量类,定义一个服务名称常量,即本身注册到 Nacos 中的服务名称。

1
2
3
4
5
6
7
public interface ApiConstants {

/**
* 服务名称
*/
String SERVICE_NAME = "xiaohashu-oss";
}

到这里,对象存储服务就将 /file/test 接口的 Feign 客户端,封装到 api 模块中了,有其他服务想要调用对象存储服务的 /file/test 接口,只需引入 xiaohashu-oss-api 模块即可。

  1. 启用Feign客户端
    编辑 XiaohashuUserBizApplication 启动类,添加 @EnableFeignClients 注解,以启用引入的 xiaohashu-oss-api 模块中定义好的 Feign 客户端。
1
2
3
@EnableFeignClients(basePackages = "com.quanxiaoha.xiaohashu")
public class XiaohashuUserBizApplication {
}
  1. 服务间调用
    以上工作完成后,就可以在用户服务中,注入 FileFeignApi 客户端,来调用对象存储服务的 /file/test 接口了。

OpenFeign 支持表单请求

针对于图片上传,普通的调用方式还不行,需要额外配置表单提交。

添加依赖:

1
2
3
4
5
6
7
<!-- Feign 表单提交 -->
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form</artifactId>
<version>3.8.0</version>
</dependency>
</dependencies>

feign-form 依赖是干嘛的?

feign-form 是一个 Feign 扩展库,专门用于处理表单数据的编码。它提供了一些增强功能,使 Feign 客户端能够更方便地处理表单提交和文件上传等操作。

表单配置类
新建一个 FeignFormConfig表单配置类。

1
2
3
4
5
6
7
8
@Configuration
public class FeignFormConfig {

@Bean
public Encoder feignFormEncoder() {
return new SpringFormEncoder();
}
}
  • SpringFormEncoder 是 Feign 提供的一个编码器,用于处理表单提交。它将对象编码为表单数据格式(如 application/x-www-form-urlencodedmultipart/form-data),以便在 HTTP 请求中使用。

封装 Feign 调用

创建一个 /rpc 包,统一放置服务间调用代码,并新建 OssRpcService 类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Component
public class OssRpcService {

@Resource
private FileFeignApi fileFeignApi;

public String uploadFile(MultipartFile file) {
// 调用对象存储服务上传文件
Response<?> response = fileFeignApi.uploadFile(file);

if (!response.isSuccess()) {
return null;
}

// 返回图片访问链接
return (String) response.getData();
}
}

将调用对象存储服务上传文件的逻辑,单独封装一层 service,并声明一个 uploadFile() 方法。方法中,若调用对象存储服务成功,则返回图片链接;否则,返回 null

Feign 请求拦截器:实现 userId 服务间透传

如果说,我们想在下游服务中获取当前请求对应的用户 ID , 比如,修改用户信息接口,会调用对象存储微服务,在对象存储微服务中,通过前面封装的上下文组件获取当前用户 ID,能拿的到吗?

为什么获取不到?

原因是网关路由转发到服务时,网关层会设置用户 ID 到请求头中,但是,服务之间调用是通过 Feign 来完成的,是没有经过网关的,下游服务再去从请求头中获取用户 ID,自然是拿不到。

如何解决上面这个问题呢?

可以为 Feign 单独配置一个请求拦截器,在调用其他服务时,将当前用户 ID 添加到请求头中,保证下游服务也能够通过上下文组件拿到用户 ID。

  1. 配置 Feign 请求拦截器
    将这个功能,一并放到上下文组件中。首先,编辑 xiaoha-spring-boot-starter-biz-context 上下文组件的 pom.xml, 添加 feign 核心依赖:
1
2
3
4
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
</dependency>

在上下文组件中,创建一个 /interceptor 包,用于放置拦截器,并新建 FeignRequestInterceptor 请求拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Slf4j
public class FeignRequestInterceptor implements RequestInterceptor {

@Override
public void apply(RequestTemplate requestTemplate) {
// 获取当前上下文中的用户 ID
Long userId = LoginUserContextHolder.getUserId();

// 若不为空,则添加到请求头中
if (Objects.nonNull(userId)) {
requestTemplate.header(GlobalConstants.USER_ID, String.valueOf(userId));
log.info("########## feign 请求设置请求头 userId: {}", userId);
}
}
}
  • 自定义 Feign 请求拦截器需继承自 RequestInterceptor 接口;

  • apply() 方法中,先通过 LoginUserContextHolder.getUserId(); 拿到当前请求对应的用户 ID;

  • 判断若不为空,则将用户 ID 添加到请求头中,以便下游服务再次获取;

  1. 自动化配置

/config 包下,新建一个 FeignContextAutoConfiguration 自动化配置类。

1
2
3
4
5
6
7
8
@AutoConfiguration
public class FeignContextAutoConfiguration {

@Bean
public FeignRequestInterceptor feignRequestInterceptor() {
return new FeignRequestInterceptor();
}
}
  • 将刚刚自定义的 FeignRequestInterceptor 请求拦截器,自动注入到 Spring 容器中。

同时,别忘了在 org.springframework.autoconfigure.AutoConfiguration.imports 文件中,添加上 FeignContextAutoConfiguration 的完整包路径。


OpenFeign组件
http://bloomivy.github.io/2025/01/22/OpenFeign组件/
作者
Bloom
发布于
2025年1月22日
许可协议