admin管理员组文章数量:1566224
某天某个地方,正在愉快的撸代码,突然异常邮件报警,赶快上服务器看日志,发现是定时任务在疯狂报错,错误如下:
No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
上古狗翻译一下,大致意思是在web请求之外使用了fegin调用微服务,急忙找源码瞅了瞅,找到了报错的地方
可以看到只要RequestAttributes为null就会抛异常,问题找到了,顺着源码分析一下,RequestAttributes为null大概有两种原因:
1.请求是web请求,但在代码执行过程中执行了异步方法,在请求结束后RequestAttributes被销毁,具体解决方法看我的另一个博客,异步操作导致异步线程获取不到主线程的request信息
2.就是我们在一个非web方法里边调用了微服务,RequestAttributes为null也会报错,知道原因我们尝试解决:
既然RequestAttributes为null,他又是一个接口,那我们可以实现以下这个接口。我们把实现类起名为NonWebRequestAttributes,下边是代码
public class NonWebRequestAttributes implements RequestAttributes {
public NonWebRequestAttributes(){
}
@Override
public Object getAttribute(String name, int scope){return null;}
@Override
public void setAttribute(String name, Object value, int scope) {
}
@Override
public void removeAttribute(String name, int scope){}
@Override
public String[] getAttributeNames(int scope){return new String[0];}
@Override
public void registerDestructionCallback(String name, Runnable callback, int scope) {
}
@Override
public Object resolveReference(String key) {
return null;
}
@Override
public String getSessionId() {
return null;
}
@Override
public Object getSessionMutex() {
return null;
}
}
现在有RequestAttributes对象的实现类了,我们就尝试注入他,找到他的RequestAttributes对象注入的拦截器,重写他起名为FeignConfig,然后注入,下边是源码
@Component
@Slf4j
public class FeignConfig implements RequestInterceptor {
public FeignConfig() {
}
@Bean
public Retryer feignRetryer() {
return new Retryer.Default(100,1000,5);
}
@Bean
public RequestContextListener requestContextListenerBean() {
return new RequestContextListener();
}
@Override
public void apply(RequestTemplate requestTemplate) {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (Objects.nonNull(requestAttributes)){
RequestContextHolder.setRequestAttributes(requestAttributes,true);
try {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = attributes.getRequest();
requestTemplate.header(HttpHeaders.AUTHORIZATION, request.getHeader(HttpHeaders.AUTHORIZATION));
}catch (Exception e){
log.info("定时任务介入,授权异常");
}
}else {
RequestContextHolder.setRequestAttributes(new NonWebRequestAttributes(), Boolean.TRUE);
HttpServletRequest httpRequest = this.getHttpServletRequestSafely();
if (null != httpRequest && null != httpRequest.getAttribute("X-Request-No")) {
requestTemplate.header("X-Request-No", httpRequest.getAttribute("X-Request-No").toString());
}
}
}
public HttpServletRequest getHttpServletRequestSafely() {
try {
RequestAttributes requestAttributesSafely = this.getRequestAttributesSafely();
return requestAttributesSafely instanceof NonWebRequestAttributes ? null : ((ServletRequestAttributes)requestAttributesSafely).getRequest();
} catch (Exception var2) {
return null;
}
}
public RequestAttributes getRequestAttributesSafely() {
RequestAttributes requestAttributes = null;
try {
requestAttributes = RequestContextHolder.currentRequestAttributes();
} catch (IllegalStateException var3) {
requestAttributes = new NonWebRequestAttributes();
}
return requestAttributes;
}
可以看出我的apply方法里边写了if判断,是因为我需要在请求微服务的时候把token带到被调用的微服务,只要你的定时任务注入了我们自己写的NonWebRequestAttributes,那么这个定时任务会始终带着他,这也是我在
这个地方捉一下异常的原因,当然这些代码还可以简化或根据自己实际情况进行编写。
最后,你学废了吗?
版权声明:本文标题:在非web请求中使用Feign完成微服务调用(定时任务,过期策略等) 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dongtai/1726604517a1077417.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论