Jersey CORS过滤器已配置,React REST GET请求仍跨域报错
Jersey+Tomcat跨域CORS配置失效,React请求预检失败解决指南
问题梳理
- 环境:RH 8.6 服务器,Tomcat部署Jersey Servlet后端,React前端实现REST交互
- 核心问题:
- React发起GET/POST请求时触发
access-control-allow-origin头不被允许跨域错误 - 配置CORS过滤器后,Postman测试响应头正常,但React请求仍失败
- 调试发现过滤器能接收GET请求,但请求无法到达Jersey资源类端点
- React请求添加
mode: 'no-cors'能收到响应头,但正常请求报错,控制台提示跨域请求被阻止,原因是预检响应的Access-Control-Allow-Headers不包含指定请求头
- React发起GET/POST请求时触发
核心原因
- OPTIONS预检请求未正确处理:React携带
Content-Type、Accept等自定义头的请求会触发浏览器OPTIONS预检,若后端未响应该请求或未配置允许的头/方法,直接导致跨域失败 - 过滤器执行顺序错误:Jersey的Servlet可能在CORS过滤器之前拦截请求,导致过滤器注入的响应头未生效,请求无法到达资源类
- CORS配置不完整:未明确允许React使用的请求头,也未将OPTIONS方法加入允许列表
分步解决方案
1. 补全CORS过滤器配置(强制覆盖OPTIONS请求)
无论使用web.xml配置还是自定义Filter类,都需确保以下配置:
- 直接响应OPTIONS预检请求,无需走业务逻辑
- 明确列出React请求中携带的所有自定义头
- 允许的方法包含GET、POST、OPTIONS
web.xml配置示例:
<filter> <filter-name>CorsFilter</filter-name> <filter-class>com.xxx.yourpackage.CorsFilter</filter-class> <init-param> <param-name>allowedOrigins</param-name> <param-value>https://your-react-domain.com</param-value> <!-- 生产环境禁用*,写具体域名 --> </init-param> <init-param> <param-name>allowedMethods</param-name> <param-value>GET,POST,OPTIONS</param-value> </init-param> <init-param> <param-name>allowedHeaders</param-name> <param-value>Content-Type,Accept</param-value> <!-- 对应React请求头 --> </init-param> </filter> <filter-mapping> <filter-name>CorsFilter</filter-name> <url-pattern>/*</url-pattern> <!-- 覆盖所有Jersey接口路径 --> <dispatcher>REQUEST</dispatcher> <dispatcher>OPTIONS</dispatcher> </filter-mapping>
自定义Filter类示例:
public class CorsFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) res; HttpServletRequest request = (HttpServletRequest) req; // 生产环境替换为你的React域名 response.setHeader("Access-Control-Allow-Origin", "https://your-react-domain.com"); response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); // 必须包含React请求的所有自定义头 response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept"); response.setHeader("Access-Control-Allow-Credentials", "true"); // 直接响应OPTIONS预检请求 if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { response.setStatus(HttpServletResponse.SC_OK); return; } chain.doFilter(req, res); } @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void destroy() {} }
2. 调整过滤器与Jersey的执行顺序
在web.xml中,将CORS过滤器的<filter-mapping>放在Jersey的<servlet-mapping>之前,确保CORS过滤器优先处理请求,避免Jersey提前拦截导致响应头未注入。
3. 修正React请求代码
移除mode: 'no-cors'配置(该模式会返回无法读取内容的不透明响应),保持请求头与后端允许的一致:
fetch('http://your-tomcat-url/api/your-resource', { method: 'GET', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' } }) .then(res => res.json()) .then(data => console.log('Success:', data)) .catch(err => console.error('Request failed:', err));
4. 浏览器工具验证预检请求
打开浏览器开发者工具Network面板,查看OPTIONS请求的响应头:
- 确认
Access-Control-Allow-Origin值为你的React域名 - 确认
Access-Control-Allow-Headers包含Content-Type、Accept - 确认
Access-Control-Allow-Methods包含OPTIONS、GET、POST
额外排查项
- 检查Tomcat全局配置(conf/web.xml)是否存在默认CORS过滤器,避免与自定义过滤器冲突
- 确认Jersey资源类的
@Path路径正确,过滤器的url-pattern覆盖该路径 - 若使用Spring Boot整合Jersey,需排查Spring的CORS配置是否与Jersey冲突
内容的提问来源于stack exchange,提问作者John kerich
相关产品推荐
相关产品推荐

