目录
实现ClientHttpRequestIntercetpor接口并重写intercept方法
Feign和OpenFeign
Feign
Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端,Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
OpenFeign
OpenFeign是springcloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
RequestInterceptor请求拦截器
RequestInterceptor是OpenFeign提供的一个拦截器,它可以在每一次接口调用之前,对这个接口进行拦截器,你可以对这个接口做一些额外的处理,例如:权限认证、添加请求头信息等等操作。
RequestInterceptor的使用步骤包括如下:
- 实现RequestInterceptor请求拦截器。
- 对实现的拦截器进行配置,分为全局配置以及局部配置。
实现RequestInterceptor请求拦截器
自定义一个类,实现RequestInterceptor接口,重写apply()方法:
package com.gitee.code.interceptor;
import feign.RequestInterceptor;
import feign.RequestTemplate;
/**
* @version 1.0.0
* @Copyright (C)
* @Description: 请求拦截器
*/
public class CustomFeignInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
// TODO 在这里可以实现一些自定义的逻辑,例如:用户认证
System.out.println("执行拦截器....");
requestTemplate.query("name","Allen") ;
requestTemplate.header(header, "secret"); //作用 :统一加 Headers :
}
}
配置类指定我们的自定义拦截器,拦截器需要继承RequestInterceptor,实现 apply(RequestTemplate requestTemplate)方法。在这个方法我们拿到了被拦截请求的RestTemplate实例,就可以往里面扔公共参数啦~
在这里调用query,就是追加一个新的query param,还有其他api如header、body等等,按需调用即可。调用header,就是向请求头中添加一个header字段,其值为secret。
全局配置拦截器
上面虽然写好了拦截器,但是OpenFeign还不知道有这个拦截器,所以还需要通过配置,告诉OpenFeign使用我自己编写的拦截器。编写一个配置类,使用@Configuration注解,并且使用@Bean注解将RequestInterceptor注入到IOC容器里面。
注意:这种方式配置的拦截器,是对所有的FeignClient都生效的。
package com.gitee.code.config;
import com.gitee.code.interceptor.CustomFeignInterceptor;
import feign.RequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @version 1.0.0
* @Description: OpenFeign 配置类
*/
@Configuration
public class FeignConfig {
/**
* 注入自定义的拦截器
*/
@Bean
public RequestInterceptor requestInterceptor() {
return new CustomFeignInterceptor();
}
}
局部配置拦截器
局部拦截器不同于全局拦截器,强调的是1对1配置【对于某一个FeignClient下的所有接口生效】,此时不需要在配置FeignConfig上面添加注解@Configuration,而是在@FeignClient注解的configuration参数指定一个配置类。示例如下所示:
@FeignClient(name = "auth",configuration = FeginConfig.class)
public interface AuthFeignService {
/**
* 该接口需要传输的http header ,需要每次手动传输header
* 比较麻烦,重复代码多
* /
@PostMapping("/role/user/isSystemAdmin1")
Boolean isSystemAdmin(@RequestBody Map entity,@RequestHeader String secret);
/**
* 拦截器 FeginHeaderInterceptor 自动配置传输参数 header,无需每次手动传输
* 大大简化接口参数,减少手写冗余代码参数
* /
@PostMapping("/role/user/isSystemAdmin2")
Boolean isSystemAdmin(@RequestBody Map entity);
}
除了上面所述在FeignClient中通过configuration指定配置项,也可以通过在配置文件【application.yml】中指定局部拦截器。
# feign 配置
feign:
client:
config:
# 这里写微服务的服务名称,例如:我这里写的是 service-provider 服务名称
# 针对 service-provider 微服务的请求,都将执行这些配置信息
service-provider:
loggerlevel: full
# 配置请求拦截器,可以多个
requestInterceptors:
- com.gitee.code.interceptor.CustomFeignInterceptor
RestTemplate集成拦截器
最近在公司打杂,让我将原本的通过Http调用下游在请求头中传递某些字段的接口进行升级改造,让我编写一个RestTemplate以实现复用。
什么是RestTemplate
RestTemplate
是 Spring 框架中用于同步客户端 HTTP 访问的类,它提供了一种简单的方式来执行 HTTP 请求并处理响应。在 RestTemplate
中,拦截器(Interceptor)是一种强大的机制,可以在请求被发送到服务器之前或响应被返回给客户端之后执行一些操作。
查询资料为什么需要RestTemplate解释如下:
Spring RestTemplate 经常被用作客户端向 Restful API 发送各种请求,在开发过程中我们会发现很多请求都会有相同的场景,如请求携带认证的 token、验证的签名、打印请求和响应日志等。在请求方法里面添加这些通用的非业务逻辑,代码显得很冗余。这个时候我们就思考,我们是不是就可以将这些非业务性代码抽取出来进行复用。
Spring 提供了 ClientHttpRequestInterceptor 接口,可以对请求进行拦截,并在其被发送至服务端之前修改请求或是增强相应的信息。
如何使用RestTemplate拦截器
实现ClientHttpRequestIntercetpor接口并重写intercept方法
拦截器1:LogInterceptor 代码
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Optional;
@Slf4j
@Component
public class LogInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
ClientHttpResponse response = clientHttpRequestExecution.execute(httpRequest, bytes);
log.info("request = {}, requestBody = {}, response = {}", httpRequest,
Optional.of(bytes).map(String::new).orElse(""), response);
return response;
}
}
拦截器2:TokenInterceptor 代码
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Slf4j
@Component
public class TokenInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
HttpHeaders headers = httpRequest.getHeaders();
headers.add("Authorization", "token");
return clientHttpRequestExecution.execute(httpRequest, bytes);
}
}
拦截器添加到RestTemplate实例
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@Configuration
public class RestTemplateConfig {
@Autowired
private LogInterceptor logInterceptor;
@Autowired
private TokenInterceptor tokenInterceptor;
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
List<ClientHttpRequestInterceptor> interceptorList = Lists.newArrayList();
// 增加多个拦截器,多个拦截器按照顺序执行
interceptorList.add(tokenInterceptor);
interceptorList.add(logInterceptor);
restTemplate.setInterceptors(interceptorList);
return restTemplate;
}
}
参考文献
feign 全局 与 局部拦截器的区分与使用_feigninterceptor局部拦截-CSDN博客
Feign Interceptor 拦截器实现全局请求参数_feign拦截器获取请求参数-CSDN博客
RestTemplate 集成拦截器_resttemplate 拦截器-CSDN博客