1、Feign 远程调用丢失请求头
/**
* ReflectiveFeign.class
* this.dispatch.get(method)).invoke(args)
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (!"equals".equals(method.getName())) {
if ("hashCode".equals(method.getName())) {
return this.hashCode();
} else {
return "toString".equals(method.getName()) ? this.toString() : ((MethodHandler)this.dispatch.get(method)).invoke(args);
}
} else {
try {
Object otherHandler = args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
return this.equals(otherHandler);
} catch (IllegalArgumentException var5) {
return false;
}
}
}
/**
* SynchronousMethodHandler.class
* this.executeAndDecode(template, options);
*/
public Object invoke(Object[] argv) throws Throwable {
// 构造请求模板
RequestTemplate template = this.buildTemplateFromArgs.create(argv);
Options options = this.findOptions(argv);
Retryer retryer = this.retryer.clone();
while(true) {
try {
return this.executeAndDecode(template, options);
} catch (RetryableException var9) {
RetryableException e = var9;
try {
retryer.continueOrPropagate(e);
} catch (RetryableException var8) {
Throwable cause = var8.getCause();
if (this.propagationPolicy == ExceptionPropagationPolicy.UNWRAP && cause != null) {
throw cause;
}
throw var8;
}
if (this.logLevel != Level.NONE) {
this.logger.logRetry(this.metadata.configKey(), this.logLevel);
}
}
}
}
/**
* 执行请求并解码
*/
Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
// 构造请求
Request request = this.targetRequest(template);
if (this.logLevel != Level.NONE) {
this.logger.logRequest(this.metadata.configKey(), this.logLevel, request);
}
long start = System.nanoTime();
Response response;
try {
response = this.client.execute(request, options);
response = response.toBuilder().request(request).requestTemplate(template).build();
} catch (IOException var12) {
if (this.logLevel != Level.NONE) {
this.logger.logIOException(this.metadata.configKey(), this.logLevel, var12, this.elapsedTime(start));
}
throw FeignException.errorExecuting(request, var12);
}
long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
if (this.decoder != null) {
return this.decoder.decode(response, this.metadata.returnType());
} else {
CompletableFuture<Object> resultFuture = new CompletableFuture();
this.asyncResponseHandler.handleResponse(resultFuture, this.metadata.configKey(), response, this.metadata.returnType(), elapsedTime);
try {
if (!resultFuture.isDone()) {
throw new IllegalStateException("Response handling not done");
} else {
return resultFuture.join();
}
} catch (CompletionException var13) {
Throwable cause = var13.getCause();
if (cause != null) {
throw cause;
} else {
throw var13;
}
}
}
}
/**
* Feign在远程调用之前要构造请求,会调用很多的拦截器
* Iterator var2 = this.requestInterceptors.iterator();
*/
Request targetRequest(RequestTemplate template) {
Iterator var2 = this.requestInterceptors.iterator();
while(var2.hasNext()) {
RequestInterceptor interceptor = (RequestInterceptor)var2.next();
interceptor.apply(template);
}
return this.target.apply(template);
}
默认的请求模板
构造的请求
2、Feign 远程调用异步情况下丢失上下文
3、解决feign远程调用丢失请求头、异步情况丢失上下文
@Override
public OrderConfirmVO getOrderConfirmVO() throws Exception {
// 获取原生请求信息
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
// 获取当前登录用户
MemberVO member = LoginInterceptor.threadLocal.get();
OrderConfirmVO orderConfirmVO = new OrderConfirmVO();
CompletableFuture<Void> addressFuture = CompletableFuture.runAsync(() -> {
// 共享原生请求信息,解决feign远程调用异步情况丢失上下文
RequestContextHolder.setRequestAttributes(attributes);
// 远程获取用户所有收货地址信息
R r = memberFeignService.memberAddresses(member.getId());
List<MemberAddressVO> addresses = r.getData("memberAddresses", new TypeReference<List<MemberAddressVO>>() {});
orderConfirmVO.setAddresses(addresses);
}, executor);
CompletableFuture<Void> itemFuture = CompletableFuture.runAsync(() -> {
// 共享原生请求信息,解决feign远程调用异步情况丢失上下文
RequestContextHolder.setRequestAttributes(attributes);
// 远程获取用户购物车信息
R r = cartFeignService.getUserCartItems();
List<CartItemVO> cartItems = r.getData("cartItems", new TypeReference<List<CartItemVO>>() {});
orderConfirmVO.setCartItems(cartItems);
}, executor).thenRunAsync(() -> {
List<CartItemVO> cartItems = orderConfirmVO.getCartItems();
List<Long> skuIds = cartItems.stream().map(item -> item.getSkuId()).collect(Collectors.toList());
R r = wareFeignService.getSkuHasStock(skuIds);
Map<Long, Boolean> skuStock = r.getData("skuStock", new TypeReference<Map<Long, Boolean>>() {});
orderConfirmVO.setSkuStock(skuStock);
}, executor);
// TODO 远程获取优惠信息
// 防重令牌
String token = UUID.randomUUID().toString();
String tokenKey = OrderConstant.ORDER_TOKEN_PREFIX + member.getId();
stringRedisTemplate.opsForValue().set(tokenKey, token, 30, TimeUnit.MINUTES);
orderConfirmVO.setOrderToken(token);
CompletableFuture.allOf(addressFuture, itemFuture).get();
return orderConfirmVO;
}
/**
* 解决feign远程调用丢失请求头、异步情况丢失上下文
*/
@Configuration
public class FeignConfig {
@Bean
public RequestInterceptor requestInterceptor() {
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate requestTemplate) {
// RequestContextHolder 获取原生请求信息
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
// 异步情况丢失上下文,request 为 null
if (attributes != null) {
// 获取原生请求
HttpServletRequest request = attributes.getRequest();
if (request != null) {
// 给新请求同步cookie
requestTemplate.header("Cookie", request.getHeader("Cookie"));
}
}
}
};
}
}