查找我们是否在线程绑定请求中而不检查异常的安全方法

问题描述 投票:2回答:1

问题

因此,我们有一个请求拦截器(伪装),它检查autowired HttpServletRequest是否有标头,然后将其传播/复制到传出请求中。我们的拦截器的工作是将标头从微服务传播到微服务,以便即使图中的最后一个微服务也具有有关谁发起请求的信息(例如租户)。

有时我们由于HTTP请求线程而称其为伪装,有时我们在启动时或从预定线程中调用它。

对于调度线程,我们希望能够在不进行尝​​试/捕获的情况下检测是否存在请求。在这种情况下,我们是发起方,我们不需要复制任何内容。

我原以为以下内容可以工作,但是我们得到了一个引发异常的代理对象:

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

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的实现改变了,那么实现的细节可能会改变(例如键),而我们在启动器中的实现会中断。但是无论如何,无论何时升级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的内部原理,它们继续使用“请求属性”。

问题,所以我们有一个请求拦截器(伪装),它检查自动连接的HttpServletRequest中的标头,然后将其传播/复制到传出的请求中。我们的拦截器的工作是...

java spring multithreading request-headers spring-cloud-feign
1个回答
0
投票

我有类似的问题,我使用RequestContextHolder检查请求是否绑定到线程。根据doc,如果没有任何RequestAttributes绑定到线程,则getRequestAttributes返回null。

© www.soinside.com 2019 - 2024. All rights reserved.