OpenFeign组件中有这么一个接口——RequestInterceptor 。我们来看一下源码中关于这个接口的介绍。
package feign;
/**
* 可以配置零个或多个请求拦截器,可以用于例如给所有请求添加请求头信息.但是不能保证拦截器的应用顺
* 序。一旦拦截器被应用,就会调用Target类中的apply(RequestTemplate)方法去创建不可变的http请
* 求,该请求通过Client类中的execute(Request, feign.Request.Options)发送。
*
* 拦截器是在设置rest模板参数后才被应用的,因此不能再拦截器中添加参数,比如不能再
* apply(RequestTemplate)方法中给/path/{foo}/bar中的foo设置参数。
* 这个类类似于RequestInterceptor.intercept()方法,可以实现读取、删除或以其他方式改变请求模板
* 的任何部分。
*/
public interface RequestInterceptor {
/**
* 可以被每个请求调用。使用RequestTemplate提供的这个方法可以添加数据。
*/
void apply(RequestTemplate template);
}
通过对该类及方法的注释可以了解到RequestInterceptor接口的apply方法可以对请求进行拦截,可以在该方法中添加请求头信息。
实践一下。
场景如下,使用拦截器在请求头中添加traceId属性,服务端可以获取到该traceId,用于日志追踪。
方式一:创建自定义拦截器+@Configuration
package com.example.rtbootconsumer.config.interceptor;
import com.example.rtbootconsumer.common.utils.TraceIdUtil;
import feign.Request;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Configuration;
/**
* @Description Feign接口请求拦截器
**/
@Configuration
public class FeignRequestInterceptor implements RequestInterceptor {
/**
* @description: 将traceId设置到请求头
*/
@Override
public void apply(RequestTemplate template) {
String traceId = TraceIdUtil.getTraceId();
if (StringUtils.isNotEmpty(traceId)) {
template.header("traceId", traceId);
}
}
}
方式二:创建自定义拦截器+配置@FeignClient注解的configuration属性
package com.example.rtbootconsumer.config.interceptor;
import com.example.rtbootconsumer.common.utils.TraceIdUtil;
import feign.Request;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Configuration;
/**
* @Description Feign接口请求拦截器
**/
public class FeignRequestInterceptor implements RequestInterceptor {
/**
* @description: 将traceId设置到请求头
*/
@Override
public void apply(RequestTemplate template) {
String traceId = TraceIdUtil.getTraceId();
if (StringUtils.isNotEmpty(traceId)) {
template.header("traceId", traceId);
}
}
}
package com.example.rtbootconsumer.feignservice;
import com.example.rtbootconsumer.pojo.User;
import com.example.rtbootconsumer.vo.ResultBody;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@FeignClient(name = "service-provider", path = "/testComm", url = "${addr.url}",configuration = FeignRequestInterceptor.class)
public interface UserFeignService {
@PostMapping(value = "/getUser")
public ResultBody getUser(@RequestBody User user);
}
也可以同时创建多个拦截器实现拦截器链的功能。
此时再创建一个拦截器FeignRequestInterceptor2,用于在请求头中设置属性名为test,值为lalala信息。
方式一:同上
package com.example.rtbootconsumer.config.interceptor;
import com.example.rtbootconsumer.common.utils.TraceIdUtil;
import feign.Request;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Configuration;
/**
* @Description Feign接口请求拦截器
**/
@Configuration
public class FeignRequestInterceptor2 implements RequestInterceptor {
/**
* @description: 将test设置到请求头
*/
@Override
public void apply(RequestTemplate template) {
String traceId = TraceIdUtil.getTraceId();
if (StringUtils.isNotEmpty(traceId)) {
template.header("test", "lalala");
}
}
}
方式二:同上,注意这里设置的@FeignClient注解的configuration属性值是两个拦截器的class数组。
package com.example.rtbootconsumer.feignservice;
import com.example.rtbootconsumer.pojo.User;
import com.example.rtbootconsumer.vo.ResultBody;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@FeignClient(name = "service-provider", path = "/testComm", url = "${addr.url}",configuration = {FeignRequestInterceptor.class,FeignRequestInterceptor2.class})
public interface UserFeignService {
@PostMapping(value = "/getUser")
public ResultBody getUser(@RequestBody User user);
@PostMapping(value = "/testList")
public ResultBody> testList(@RequestBody List list);
}
在创建并配置拦截器时有两点需要特别注意。