如何解决跨域
什么是跨域问题?
跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对 JavaScript 施加的安全限制。
什么是同源?
所谓同源是指,域名,协议,端口均相同
http://www.funtl.com --> http://admin.funtl.com 跨域http://www.funtl.com --> http://www.funtl.com 非跨域http://www.funtl.com --> http://www.funtl.com:8080 跨域http://www.funtl.com --> https://www.funtl.com 跨域
使用 CORS(跨资源共享)解决跨域问题
CORS 是一个 W3C 标准,全称是”跨域资源共享”(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出 XMLHttpRequest 请求,从而克服了 AJAX 只能同源使用的限制。
CORS 需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE 浏览器不能低于 IE10
整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS 通信与同源的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉
因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨源通信
CORS 与 JSONP 的比较
CORS 与 JSONP 的使用目的相同,但是比 JSONP 更强大。
JSONP 只支持 GET 请求,CORS 支持所有类型的 HTTP 请求。JSONP 的优势在于支持老式浏览器,以及可以向不支持 CORS 的网站请求数据。
概念与 CORS/JSONP 对比正确,但生产排障需要更深一层:预检(preflight)的触发条件与缓存、简单请求与非简单请求的分野、带凭证跨域的三大约束、以及”跨域配置放哪一层”的架构决策。本文补全成可直接排障的 CORS 手册。
两类请求与预检机制
简单请求(同时满足:GET/HEAD/POST + 仅简单头 + Content-Type 限 text/plain、multipart/form-data、application/x-www-form-urlencoded):浏览器直接发请求,带 Origin 头,服务端回 Access-Control-Allow-Origin 即放行。
非简单请求:浏览器先发 OPTIONS 预检(带 Origin + Access-Control-Request-Method + -Headers),服务端允许才发真实请求。预检触发条件=不满足简单请求任一条件(如 POST JSON、自定义头 X-Token、PUT/DELETE)。
预检优化:Access-Control-Max-Age 缓存预检结果(如 86400),同资源同方法同头组合不再重复预检——网关层设置 Max-Age 可显著减少 OPTIONS 流量。
带凭证跨域的三大约束(最高频踩坑)
请求带 Cookie/Authorization(fetch 的 credentials:’include’ / xhr 的 withCredentials=true)时:
- 服务端
Access-Control-Allow-Origin**不能为***,必须回精确 Origin - 必须加
Access-Control-Allow-Credentials: true - 客户端必须显式开启凭证模式(默认不带)
三者缺一即报”credentials flag 与 Allow-Origin * 冲突”类错误——**”明明配了 CORS 还跨域失败”八成死在这里**。
响应头速查
| 头 | 作用 |
|---|---|
| Access-Control-Allow-Origin | 允许的源(精确值或 *,凭证时禁 *) |
| Access-Control-Allow-Credentials | 允许带凭证 |
| Access-Control-Allow-Methods | 预检允许的方法 |
| Access-Control-Allow-Headers | 预检允许的自定义头 |
| Access-Control-Expose-Headers | 允许 JS 读取的响应头(默认仅简单头) |
| Access-Control-Max-Age | 预检缓存秒数 |
方案谱系与架构决策
- 网关/反代统一配置(推荐):Nginx add_header / Spring Cloud Gateway 的 CorsWebFilter / 云网关规则——单点配置、避免各服务注解散落不一致;注意不要网关与服务双层重复加头(重复的 Allow-Origin 头会导致浏览器拒绝)
- 服务级:Spring @CrossOrigin / CorsRegistry(Boot 项目内部服务直连场景)
- 开发期:vite/webpack devServer proxy(把跨域消灭在本地反代,生产无 CORS 配置)
- 同域化(根治):前端与 API 同域部署(Nginx 反代 /api → 后端)或子域+同站 Cookie——能同域就不跨域,CORS 配置面归零
- JSONP:仅遗留系统兼容,新代码禁用(GET only + 注入风险)
- postMessage / WebSocket:特殊通道(iframe 通信 / WS 本身不受同源限制)
排障 checklist(按序检查)
- 报错是”无 Allow-Origin”(服务端没配/配错层)还是”credentials 冲突”(* 与凭证矛盾)?
- OPTIONS 预检是否 200/204 且带齐 Allow-Methods/Headers?(405/404=服务端没处理 OPTIONS,常被鉴权拦截器挡下——鉴权要放行 OPTIONS)
- 是否双层加头(网关+服务)导致重复头?
- 自定义头是否列入 Allow-Headers?
- 缓存的旧预检/旧响应头干扰?(Max-Age 期内改配置不生效,需等过期或换资源)
安全提醒
Allow-Origin: *+ 敏感接口 = 任何网站可读取响应(无凭证时);凭证场景精确 Origin 白名单且校验(防 Origin 伪造不了但配置错误放行)- CORS 防的是”浏览器代读”,不是授权机制——接口鉴权永远独立于 CORS 配置
跨域的答案 = 同源策略是浏览器安全基线、CORS 是服务端声明的豁免清单、预检与凭证约束是豁免的细则;工程上”网关单点配置 + 能同域则同域 + 排障五步 checklist”三件套,覆盖 95% 的跨域问题。











