gpt4 book ai didi

java - 在不检查异常的情况下查找我们是否在线程绑定(bind)请求中的安全方法

转载 作者:行者123 更新时间:2023-12-05 01:01:59 25 4
gpt4 key购买 nike

问题

所以我们有一个请求拦截器 (Feign),它检查 autowired HttpServletRequest 的 header ,然后将这些传播/复制到传出请求。我们的拦截器的工作是将 header 从微服务传播到微服务,这样即使图中的最后一个微服务也有关于谁发起请求的信息(例如租户)。

有时我们调用 feign 作为 HTTP 请求线程的结果,有时我们在启动时或从调度的线程中调用它。

在调度线程的情况下,我们希望能够检测请求是否存在而无需执行 try/catch。这是我们作为发起方,不需要复制任何东西的情况。

我期望下面的工作,但我们得到一个抛出异常的代理对象:

以下检查失败,因为 this.request 不为空:

this.request!=null && this.request.getHeader("X-Application")

出现以下错误:

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/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

我理解错误。我想避免做类似这样的明显解决方法:

当前的解决方法 - 笨拙和糟糕

//TODO: Review this
boolean requestExists = true;
try{
request.getHeader(APPLICATION_HEADER);
}catch (IllegalStateException e ){
requestExists = false;
}

导致问题的当前代码

   public class ServiceNameFeignInterceptor implements RequestInterceptor {
private static final Logger log = LoggerFactory.getLogger(ServiceNameFeignInterceptor.class);
final TenantIdResolver tenantResolver;
final ApplicationNameResolver appResolver;
private final String APPLICATION_HEADER = "X-Application";
private final String TENANT_ID = "X-Tenant-Id";
...
@Autowired
HttpServletRequest request;

public void apply(RequestTemplate requestTemplate) {
...

if (this.request!=null && this.request.getHeader("X-Application") != null) {
log.info("Application header found in the request !!!");
requestTemplate.header("X-Application", new String[]{this.request.getHeader("X-Application")});
requestTemplate.header("X-Tenant-Id", new String[]{this.request.getHeader("X-Tenant-Id")});

} else {
log.info("Setting {} as {} for URL {} ", new Object[]{"X-Application", appName, requestTemplate.url()});
requestTemplate.header("X-Application", new String[]{appName});
requestTemplate.header("X-Tenant-Id", new String[]{appName});
}

}

当前选项

如果可能,请纠正我以下几点或提出更好的选择。

目前我想到了三个选项:

  1. 使用 try/catch 解决方案(最不受欢迎)

  2. 检查线程局部变量是否存在请求

  3. 传递我们自己的附加线程局部变量,这将是一个标志(我们不在请求上下文中)。

问题

我不喜欢 1,因为捕获异常的代价很高,而且它们可能会掩盖任何真正的错误。

我不喜欢 2,因为如果 spring 实现发生变化,实现细节可能会发生变化(例如 key ),并且我们在 starter 中的实现会中断。但无论如何,每当升级 spring boot 时,各种次要或主要的事情都需要修复。

我喜欢选项 3,因为在调用我们的假客户端之前设置标志是一种有意识的行为。因此不存在错误未被注意到的风险。

意见、选择、解决方案?

更新

其中一位团队成员建议我们使用:new NamedThreadLocal("Request attributes");

他们建议这样做是因为在以下位置实现:

https://github.com/spring-projects/spring-framework/blob/master/spring-web/src/main/java/org/springframework/web/context/request/RequestContextHolder.java#L50

https://github.com/spring-projects/spring-framework/blob/master/spring-web/src/main/java/org/springframework/web/context/request/RequestContextHolder.java#L107

所以我们会使用类似的东西:

ThreadLocal<RequestAttributes> requestAttributesHolder = new NamedThreadLocal("Request attributes");
RequestAttributes attributes = (RequestAttributes)requestAttributesHolder.get();
boolean requestExists = attributes != null;

但这在很大程度上取决于 spring 的内部结构,并且它们继续使用“请求属性”。

最佳答案

我有一个类似的问题,我使用 RequestContextHolder 来检查请求是否绑定(bind)到线程。根据doc ,如果没有 RequestAttributes 绑定(bind)到线程,getRequestAttributes 返回 null。

RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
if (attrs == null) {
return;
}

关于java - 在不检查异常的情况下查找我们是否在线程绑定(bind)请求中的安全方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55845256/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com