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

Tomcat Jersey处理OPTIONS预检请求时阻塞服务器问题求助

解决Tomcat 7 + Jersey跨源OPTIONS预检请求延迟阻塞问题

针对你遇到的跨源OPTIONS请求随机延迟5-10秒、阻塞整个服务器,且仅在浏览器等跨源工具触发时出现的问题,结合你的代码和排查信息,我整理了几个核心排查方向和解决方案:

一、最可能的根源:OPTIONS请求未被及时终止,触发不必要的资源匹配

你的EnterpriseAPIRequestFilter在处理OPTIONS请求时只是简单return,这会让请求继续向下流转,尝试匹配Jersey的资源方法。如果你的API没有定义对应的OPTIONS资源方法,Jersey会进入错误处理流程,这就是延迟的主要来源,甚至会占用线程导致服务器阻塞。

修正方案:直接终止OPTIONS请求并返回CORS响应

修改你的EnterpriseAPIRequestFilter,在检测到OPTIONS请求时,直接通过ctx.abortWith()返回带CORS头的响应,终止请求流程:

@PreMatching @Priority(value = 1) @Provider 
public class EnterpriseAPIRequestFilter implements ContainerRequestFilter { 
    @Context private HttpServletRequest sr; 
    @Context private HttpServletResponse response; // 新增注入HttpServletResponse
    private Logger logger = Logger.getLogger(EnterpriseAPIRequestFilter.class); 

    public void filter(ContainerRequestContext ctx) throws IOException { 
        logger.info("Request Received for :" + sr.getPathInfo()); 
        logger.info("Remote IP :" + sr.getRemoteAddr()); 
        // 注意:这里你写的是sr.getLocalAddr()(服务器IP),如果是要打印客户端主机名,应该是sr.getRemoteHost(),但后者会触发DNS解析,后面会提到
        logger.info("Remote Host :" + sr.getLocalAddr()); 

        if (sr.getMethod().equalsIgnoreCase("OPTIONS")) {
            // 直接构建CORS响应,终止请求
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "OPTIONS, GET, POST, DELETE, PUT");
            response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, X-Codingpedia, channelRole, channelauthkey,channeltype,channelname,channelidentifier,orgid,id,channelOrgId,key,employeeId,subRole");
            ctx.abortWith(Response.ok().build()); // 立即返回200响应,终止后续流程
            return;
        }

        // 原有的认证逻辑放在这里
        Authenticator authenticator = new Authenticator(); 
        MultivaluedMap<String, String> headers = ctx.getHeaders(); 
        String role = headers.getFirst("channelRole"); 
        String locale = headers.getFirst("locale"); 
        // MORE CODE EXISTS HERE. 
    } 
}

同时可以考虑移除单独的CORSResponseFilter,避免重复添加响应头,减少不必要的处理。

二、潜在坑点:DNS反向解析导致的阻塞

看你的日志代码里有一行logger.info("Remote Host :" + sr.getLocalAddr());——这明显是笔误(getLocalAddr()是服务器自身的IP),如果你实际代码中是调用sr.getRemoteHost()来获取客户端主机名,那就要注意了:

Tomcat默认enableLookups="true",调用getRemoteHost()时会尝试反向解析客户端IP到主机名。如果客户端IP无法被DNS服务器解析(比如内网IP、动态IP),这个过程会阻塞线程,导致请求延迟5-10秒(DNS超时时间),甚至耗尽Tomcat线程池,阻塞所有请求。

解决方法:

  1. 修正日志代码,如果你不需要客户端主机名,直接用sr.getRemoteAddr()(客户端IP)即可,避免调用getRemoteHost()。
  2. 强制关闭Tomcat的DNS解析:修改conf/server.xml中的Connector配置,添加enableLookups="false":
<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443"
           enableLookups="false"/>

三、优化Tomcat连接器,避免阻塞式IO导致的线程耗尽

Tomcat 7默认使用BIO连接器(阻塞式IO),每个请求占用一个线程。如果OPTIONS请求因为上述原因阻塞,会快速耗尽线程池,导致其他请求无法处理。建议切换到NIO连接器(非阻塞式),并调整线程池参数:

修改conf/server.xml:

<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
           connectionTimeout="20000"
           maxThreads="200"
           acceptCount="100"
           enableLookups="false"
           URIEncoding="UTF-8"/>

NIO连接器能更高效地处理并发请求,减少阻塞带来的影响。

四、其他排查方向

  • 检查Jersey与Tomcat的兼容性:确保你使用的Jersey版本和Tomcat 7兼容,推荐使用Jersey 2.25.1这类稳定版本。
  • 排查全局CORS配置冲突:如果你的Tomcat web.xml中配置了全局CORS过滤器,可能和Jersey的过滤器冲突,建议统一使用一种方式处理CORS。
  • 验证浏览器预检缓存:浏览器会缓存OPTIONS预检响应,随机延迟可能是缓存失效时触发的新请求,可以通过浏览器开发者工具查看Access-Control-Max-Age头是否正确设置,延长缓存时间减少预检次数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 10:09:07