ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

深入解析CORS跨域问题与解决方案

深入解析CORS跨域问题与解决方案 1. 跨域问题的本质与产生场景跨域Cross-Origin Resource Sharing简称CORS是现代Web开发中最常见的安全限制机制之一。当我在2013年第一次遇到跨域问题时控制台那个红色的Access-Control-Allow-Origin错误让我困惑了整整两天。本质上跨域限制是浏览器实施的安全策略它阻止一个源的JavaScript代码与另一个源的资源进行交互。这种限制主要出现在以下典型场景前端部署在https://example.com但需要调用https://api.example.com的接口本地开发时http://localhost:3000访问测试环境APIhttps://test-api.com使用CDN资源时主站与CDN域名不一致第三方服务集成如支付、地图等SDK关键点跨域限制是浏览器的行为不是服务器的限制。通过Postman等工具直接请求接口能成功但通过浏览器就会失败这正是浏览器安全策略在起作用。2. CORS工作原理深度解析2.1 同源策略基础同源策略要求协议域名端口三者完全相同。例如https://example.com/index.html 与 https://example.com/api/users → 同源http://example.com 与 https://example.com → 不同源协议不同example.com 与 api.example.com → 不同源域名不同localhost:3000 与 localhost:8080 → 不同源端口不同2.2 CORS核心机制CORS通过HTTP头部来实现跨域控制主要涉及以下头部请求头响应头作用OriginAccess-Control-Allow-Origin声明允许的源Access-Control-Request-MethodAccess-Control-Allow-Methods声明允许的方法Access-Control-Request-HeadersAccess-Control-Allow-Headers声明允许的头部-Access-Control-Allow-Credentials是否允许携带凭证-Access-Control-Max-Age预检请求缓存时间2.3 简单请求与预检请求根据请求的复杂性CORS处理分为两种模式简单请求需同时满足方法为GET/HEAD/POST之一仅含以下头部AcceptAccept-LanguageContent-LanguageContent-Type仅限application/x-www-form-urlencoded、multipart/form-data、text/plain预检请求Preflight触发条件使用PUT/DELETE等非简单方法包含自定义头部如X-Auth-TokenContent-Type为application/json等非简单值3. 服务端CORS配置实战3.1 Node.js示例Expressconst express require(express); const app express(); // 基础CORS中间件 app.use((req, res, next) { const allowedOrigins [https://example.com, http://localhost:3000]; const origin req.headers.origin; if (allowedOrigins.includes(origin)) { res.setHeader(Access-Control-Allow-Origin, origin); } res.header(Access-Control-Allow-Methods, GET, POST, PUT, DELETE); res.header(Access-Control-Allow-Headers, Content-Type, Authorization); res.header(Access-Control-Allow-Credentials, true); res.header(Access-Control-Max-Age, 86400); if (req.method OPTIONS) { return res.sendStatus(200); } next(); }); // 你的路由...3.2 Nginx配置location /api/ { if ($http_origin ~* (https://example.com|http://localhost:3000)) { add_header Access-Control-Allow-Origin $http_origin; add_header Access-Control-Allow-Methods GET, POST, OPTIONS; add_header Access-Control-Allow-Headers DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization; add_header Access-Control-Expose-Headers Content-Length,Content-Range; add_header Access-Control-Max-Age 1728000; add_header Access-Control-Allow-Credentials true; } if ($request_method OPTIONS) { return 204; } proxy_pass http://backend; }3.3 Spring Boot配置Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/api/**) .allowedOrigins(https://example.com, http://localhost:3000) .allowedMethods(GET, POST, PUT, DELETE) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600); } }4. 前端处理跨域的实用技巧4.1 Fetch API的正确用法// 带凭证的请求 fetch(https://api.example.com/data, { credentials: include, headers: { Content-Type: application/json, Authorization: Bearer ${token} } }) .then(response { if (!response.ok) throw new Error(Network response was not ok); return response.json(); }) .catch(error { console.error(Fetch error:, error); });4.2 常见问题解决方案开发环境代理配置webpack/vite// vite.config.js export default { server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true, rewrite: path path.replace(/^\/api/, ) } } } }图片跨域处理img crossoriginanonymous srchttps://cdn.example.com/image.jpg字体跨域问题font-face { font-family: MyFont; src: url(https://cdn.example.com/font.woff2) format(woff2); font-display: swap; }5. 高级场景与疑难排查5.1 携带Cookie的跨域请求必须满足三个条件服务端设置Access-Control-Allow-Credentials: trueAccess-Control-Allow-Origin不能为*必须明确指定域名前端设置credentials: include5.2 预检请求缓存优化通过设置Access-Control-Max-Age可以减少预检请求次数Access-Control-Max-Age: 86400 # 缓存1天5.3 常见错误排查错误信息可能原因解决方案Missing CORS header服务端未返回CORS头检查服务端中间件Credential not supported使用通配符*但需要凭证指定具体域名Preflight channel failed预检请求未返回204确保OPTIONS请求正确处理Invalid CORS request请求头包含非法字符检查自定义头格式6. 替代方案与安全考量当无法修改服务端配置时可考虑JSONP仅限GET请求function handleResponse(data) { console.log(Received:, data); } const script document.createElement(script); script.src https://api.example.com/data?callbackhandleResponse; document.body.appendChild(script);反向代理location /external-api/ { proxy_pass https://target-api.com/; proxy_set_header Host target-api.com; proxy_set_header X-Real-IP $remote_addr; }安全注意事项不要随意设置Access-Control-Allow-Origin: *敏感操作需要验证Origin头防止CSRF生产环境应限制允许的HTTP方法定期审查CORS策略避免过度宽松在实际项目中我遇到过一个典型案例某电商网站因为CDN域名未加入CORS白名单导致所有字体文件加载失败。通过Chrome开发者工具的Network面板可以清晰看到被拦截的请求和具体的CORS错误信息这种可视化调试方式极大提高了排查效率。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进