You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

HttpServletRequest调用getHeader获取请求头参数长时间阻塞问题求助

根因排查方向

  • 首先排查代码中getIpAdrress(拼写存在错误,正确为Address)方法的实现逻辑:大部分场景下,获取IP的方法会迭代遍历所有请求头(比如X-Forwarded-For、Proxy-Client-IP等多个头),如果方法内部有不合理的同步锁、或者依赖了外部查询(比如IP库反查、DNS解析),会导致阻塞误判为getHeader方法本身的问题,建议先注释掉IP获取逻辑单独测试getHeader("language")的耗时确认根因。
  • 检查Tomcat/Undertow容器的请求解析配置:Spring Boot 2.3.4默认内置Tomcat 9.0.38,如果开启了请求头的安全校验、或者配置了过大的maxHeaderCount/maxHttpHeaderSize,容器在解析请求头时会加锁读取输入流,高并发场景下会出现阻塞。对应检查配置项:
    # Tomcat头配置检查
    server.tomcat.max-http-header-size=8KB
    server.tomcat.max-header-count=100
    server.tomcat.parse-body-methods=POST
    
  • 排查是否有自定义的ServletRequestWrapper实现:如果项目里有对请求做包装重写了getHeader方法,比如统一解密请求头、或者从缓存/分布式存储中读取头信息,额外的IO操作会导致阻塞,建议打栈快照确认getHeader方法的实际调用链路:
    # 阻塞时执行jstack获取调用栈
    jstack <进程ID> > stack.log
    # 搜索getHeader关键字看实际调用的实现类
    
  • 检查JVM的JNI调用或本地方法阻塞:getHeader底层依赖容器的本地实现,如果服务器的熵池不足,即使已做过SecureRandom优化,若容器的SSL握手/请求解析逻辑依赖/dev/random,还是会出现阻塞,验证方法:
    # 查看熵池大小
    cat /proc/sys/kernel/random/entropy_avail
    # 低于200的话就是熵池不足,直接安装haveged解决
    yum install haveged -y && systemctl start haveged && systemctl enable haveged
    # 同时确认JVM启动参数加了
    -Djava.security.egd=file:/dev/./urandom
    

可行解决方案

  1. 先做根因定位:在getIpAdrress执行前后、getHeader("language")执行前后分别加时间戳打印,确认具体阻塞的代码行,排除误判
  2. 如果确认是Tomcat原生getHeader阻塞:升级Tomcat版本到9.0.60+,该版本修复了高并发下请求头解析的锁竞争问题,Spring Boot 2.3.x可以单独指定Tomcat版本:
    <!-- pom.xml里覆盖Tomcat版本 -->
    <properties>
        <tomcat.version>9.0.65</tomcat.version>
    </properties>
    
  3. 替换内置容器为Undertow:Undertow的请求头解析是无锁实现,高并发场景下性能远高于Tomcat,替换方式:
    <!-- 排除Tomcat依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <!-- 引入Undertow -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-undertow</artifactId>
    </dependency>
    
  4. 对语言头做降级处理:如果业务允许,新增默认值逻辑,避免头解析阻塞影响所有请求:
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){
        logger.debug(".........................preHandle start .........................");
        // 异步获取IP避免阻塞主链路
        CompletableFuture.runAsync(() -> logger.info("================== REQUEST IP:{} ==================",this.getIpAdrress(request)));
        String languageCode = "zh"; // 默认值
        try {
            // 加超时控制,超过10ms直接用默认值
            languageCode = CompletableFuture.supplyAsync(() -> request.getHeader("language"))
                    .get(10, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            logger.warn("get language header timeout, use default zh");
        }
        LOGGER.info("================== request header languageCode:{} ================== ",languageCode);
        LocaleContextHolder.setLocale(new Locale(LanguageEnum.getName(Objects.requireNonNullElse(languageCode, "zh"))));
        return true;
    }
    

内容的提问来源于stack exchange,提问作者bob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 11:06:02