概述
还记得我们之前创建订单的流程吗?
通过网关调用 order-service 的 create
方法,然后 order-service 再通过 feign 调用 account-service 的 reduce
和 product-service 的 deduct
方法进行业务逻辑处理。
当我们项目整合好 oauth2 后再来调用之前的方法发现调用异常,查看后端日志发现如下的错误信息:
org.springframework.security.authentication.InsufficientAuthenticationException: Full authentication is required to access this resource
Request processing failed; nested exception is feign.FeignException$Unauthorized: status 401 reading AccountFeign#reduce(String,BigDecimal)
错误信息告诉我们是接口未授权导致访问异常,实际上我们已经将 access_token 放在了 header 上,如下:
最后通过对自定义异常类进行跟踪发现是 access_token 经过 order-service 访问 account-service 时丢失了,获取的 accessToken 为 null。
本节主要是来解决使用 feign 调用时 access_token 丢失的问题。
代码示例
Feign 支持请求拦截器,在发送请求前,可以对发送的模板进行操作,例如设置请求头等属性,自定请求拦截器只需要实现 RequestInterceptor
接口,该接口的方法有 RequestTemplate 类型的参数,我们可以根据实际情况对请求的信息进行调整。
public interface RequestInterceptor {
void apply(RequestTemplate var1);
}
我们要实现的功能很简单,就是取出原来的请求头,再将其传递给下游服务,在 order-service 中建立 FeignRequestInterceptor
并给其添加 @Configuration
注解,代码如下:
/**
* Description:
* 微服务之间feign调用请求头丢失的问题
* @author javadaily
* @date 2020/02/24 9:28
*/
@Configuration
@Slf4j
public class FeignRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
HttpServletRequest httpServletRequest = getHttpServletRequest();
if(httpServletRequest!=null){
Map<String, String> headers = getHeaders(httpServletRequest);
// 传递所有请求头,防止部分丢失
//此处也可以只传递认证的header
//requestTemplate.header("Authorization", request.getHeader("Authorization"));
for (Map.Entry<String, String> entry : headers.entrySet()) {
template.header(entry.getKey(), entry.getValue());
}
log.debug("FeignRequestInterceptor:{}", template.toString());
}
}
private HttpServletRequest getHttpServletRequest() {
try {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
} catch (Exception e) {
return null;
}
}
/**
* 获取原请求头
*/
private Map<String, String> getHeaders(HttpServletRequest request) {
Map<String, String> map = new LinkedHashMap<>();
Enumeration<String> enumeration = request.getHeaderNames();
if(enumeration!=null){
while (enumeration.hasMoreElements()) {
String key = enumeration.nextElement();
String value = request.getHeader(key);
map.put(key, value);
}
}
return map;
}
}
完成配置后重启服务器,再次调用 create 方法,正常返回响应结果。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于