Ngrok环境下Angular+SpringBoot的CORS异常:POST正常GET请求失败
Ngrok跨域问题:POST正常但GET请求失败(刷新前端后触发CORS错误)
问题场景
- 用两个免费Ngrok地址分别映射本地Angular服务(localhost:4200)和SpringBoot后端服务(localhost:8080)
- 前端通过Ngrok后端地址发起请求时,POST请求正常,GET请求触发CORS错误
- 直接访问Ngrok后端地址无异常
- 首次请求一切正常,刷新前端后出现问题
当前使用的CORS过滤器代码
@Component public class CorsFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); response.setHeader("Access-Control-Max-Age", "7200"); response.setHeader("Access-Control-Allow-Headers", "Origin, Authorization, Content-Type, xsrf-token, X-Requested-With, Accept, X-Auth-Token"); response.addHeader("Access-Control-Expose-Headers", "xsrf-token"); if ("OPTIONS".equals(request.getMethod())) { response.setStatus(HttpServletResponse.SC_OK); } else { filterChain.doFilter(request, response); } } }
解决方案
- 修正Origin配置(针对带凭证的请求)
如果你的Angular请求携带了Cookie、认证令牌等凭证(withCredentials: true),Access-Control-Allow-Origin不能设为*,需要动态获取请求的Origin并返回:
String origin = request.getHeader("Origin"); response.setHeader("Access-Control-Allow-Origin", origin); response.setHeader("Access-Control-Allow-Credentials", "true");
- 提升过滤器优先级
确保CORS过滤器最先执行,避免其他过滤器(如Spring Security)提前拦截请求导致跨域头未正确设置。添加@Order注解:
@Component @Order(Ordered.HIGHEST_PRECEDENCE) public class CorsFilter extends OncePerRequestFilter { // 原有代码... }
排查浏览器预检缓存
Access-Control-Max-Age: 7200会让浏览器缓存OPTIONS预检请求结果2小时,若期间Ngrok域名变化(免费版可能重启后变更),会导致缓存不匹配。可临时将Max-Age设为0,或清除浏览器缓存测试。改用Spring Boot官方CORS配置
替换自定义过滤器,使用Spring MVC提供的全局CORS配置,兼容性更好:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") // 若带凭证,替换为你的Ngrok前端地址 .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("Origin", "Authorization", "Content-Type", "xsrf-token", "X-Requested-With", "Accept", "X-Auth-Token") .exposedHeaders("xsrf-token") .allowCredentials(true) // 需携带凭证时开启 .maxAge(7200); } }
内容的提问来源于stack exchange,提问作者Rodrigo Leite
相关产品推荐
相关产品推荐

