如何配置Tomcat解决Access-Control-Allow-Origin通配符与凭证模式冲突
刚好之前做类似演示项目时踩过这个CORS的坑,给你两个靠谱的解决办法:
方案1:动态设置允许的Origin(推荐用于演示场景)
因为你的本地IP每次联网可能变化,直接在Tomcat里动态读取请求头里的Origin,把它设置到响应的Access-Control-Allow-Origin里,同时必须开启Access-Control-Allow-Credentials才能让会话凭证生效。另外别忘了处理OPTIONS预检请求——带凭证的跨域请求会先发送这个请求做校验。
修改你的Servlet代码:
@Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest httpReq = (HttpServletRequest) req; HttpServletResponse httpRes = (HttpServletResponse) res; // 获取请求发起的源地址 String requestOrigin = httpReq.getHeader("Origin"); // 动态设置允许的源为请求的Origin if (requestOrigin != null) { httpRes.setHeader("Access-Control-Allow-Origin", requestOrigin); } // 必须开启这个头,凭证模式才会生效 httpRes.setHeader("Access-Control-Allow-Credentials", "true"); // 允许的请求方法(根据你的业务调整) httpRes.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); // 允许的请求头(匹配你fetch里用到的Content-Type等) httpRes.setHeader("Access-Control-Allow-Headers", "Content-Type"); // 处理OPTIONS预检请求,直接返回200即可 if ("OPTIONS".equalsIgnoreCase(httpReq.getMethod())) { httpRes.setStatus(HttpServletResponse.SC_OK); return; } // 你的原有业务逻辑代码... }
这样不管你的本地IP是192.168.x.x还是其他,同一局域网内的请求都会被自动允许,同时会话凭证也能正常携带。
方案2:用React代理避免跨域(适合开发阶段)
React开发服务器支持代理配置,让前端请求自动转发到Tomcat后端,这样前端和代理服务器同域,就彻底绕开了CORS限制。
步骤很简单:
- 在React项目的
package.json里添加proxy字段:
"proxy": "http://localhost:8080"
- 修改你的fetch代码,把绝对路径改成相对路径:
// 不再写具体IP,直接用相对路径访问后端接口 return fetch("/graphql", { method: "POST", body: JSON.stringify({ query: query, params: params }), credentials: "include" // 同域下凭证会自动携带,无需额外配置 });
- 重启React开发服务器,现在观众访问
http://192.168.0.18:3000时,所有后端请求会被代理到Tomcat的8080端口,浏览器不会有任何跨域报错,会话也能正常维持。
为什么原来的方法行不通?
浏览器的CORS规则有明确限制:当请求的credentials模式是include时,响应头的Access-Control-Allow-Origin不能用通配符*,必须是具体的源地址,同时必须搭配Access-Control-Allow-Credentials: true。你之前用*时浏览器直接拒绝了响应;而设为omit的话,浏览器不会携带Cookie等凭证,自然无法维持会话。
内容的提问来源于stack exchange,提问作者Alkis Mavridis
相关产品推荐
相关产品推荐

