什么是跨域
跨域访问是指请求一个与自身资源不同源(不同的域名、协议或端口)的资源。不同源可以是不同的域名、协议或端口。
跨域(CORS)不是协议,不是语言特性,不是前端后端技术差异。
它的本质是浏览器为保护用户的 Cookie/Token/隐私而设置的一种安全策略(Same-Origin Policy 同源策略)。
- 跨域只存在于浏览器环境中
- 服务端 → 服务端 没有跨域问题
- Curl、Postman、Node.js 全部不跨域
跨域访问是指请求一个与自身资源不同源(不同的域名、协议或端口)的资源。不同源可以是不同的域名、协议或端口。浏览器判断是否同源:协议(http/https)、域名、端口,只要有一个不同就属于跨域。
浏览器出于安全考虑设置了同源策略,限制了从脚本内发起跨域请求。但在实际应用中,经常会发生跨域访问。为此,W3C 提供了一个标准的跨域解决方案:跨域资源共享(Cross-Origin Resource Sharing,CORS),支持安全的跨域请求和数据传输。
浏览器将 CORS 请求分为以下两类:
- 简单请求
- 预检请求:防止资源被本来没有权限的请求修改的保护机制。浏览器会在发送实际请求之前使用
OPTIONS方法发送一个预检请求,从而获知服务端是否允许该跨域请求。服务端确认允许后,才会发起实际的 HTTP 请求。
简单请求
请求满足如下所有条件,为简单请求:
- 请求方法是如下之一:
HEADGETPOST
- HTTP 头信息不超过以下几种字段:
Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragmaDPRDownlinkSave-DataViewport-WidthWidth
Content-Type的值仅限下列几种:text/plainmultipart/form-dataapplication/x-www-form-urlencoded
预检请求
不符合简单请求条件的请求,会在正式通信之前触发一个 OPTIONS 请求进行预检,即浏览器要先问服务端:我可以访问吗,会不会有危险。
这时候就发一个OPTIONS请求,不带任何业务数据:OPTIONS /api/user。这类请求为预检请求。预检请求会在请求头中附带一些正式请求的信息给服务端,主要有:
Origin:请求源信息。Access-Control-Request-Method:接下来的请求类型,如 POST、GET 等。Access-Control-Request-Headers:接下来的请求中包含的用户显式设置的 Header 列表
服务端收到预检请求后,会根据上述附带的信息判断是否允许跨域,通过响应头返回对应的信息:
Access-Control-Allow-Origin:允许跨域的 Origin 列表。Access-Control-Allow-Methods:允许跨域的方法列表。Access-Control-Allow-Headers:允许跨域的 Header 列表,允许前端带哪些自定义headerAccess-Control-Expose-Headers:允许暴露的 Header 列表。Access-Control-Max-Age:最大的浏览器缓存时间,单位:秒。Access-Control-Allow-Credentials:是否允许发送 Cookie。
浏览器会根据返回的 CORS 信息判断是否继续发送真实的请求。以上行为都是浏览器自动完成的,服务端只需要配置特定的 CORS 规则。
浏览器确认没问题后,再发真正的POST请求。
浏览器为什么阻止跨域请求
为了安全。因为用户访问 attacker.com,如果浏览器允许跨域,attacker.com 可以直接用用户在浏览器里的 cookie 去请求银行网站:GET https://bank.com/transfer?to=hacker&money=100000000
浏览器会自动带着用户的 cookie 发出去。这就叫 CSRF(跨站请求伪造),所以浏览器必须阻止跨域。
跨域处理方式
服务端设置CORS头
在API上设置:
Access-Control-Allow-Origin: https://你的前端域名
用NGINX反向代理
前端请求:/api ,NGINX 代理到 proxy_pass http://backend:8080;,这样浏览器看到的域名始终是前端域名 → 不跨域。
前端dev-server代理(仅开发环境使用)
前端在本地启动时,页面地址是:localhost:3000, 如果接口是 http://api.example.com 直接访问就会跨域。这时候 dev-server 启动了一个本地HTTP服务,代理规则告诉它:
所有 /api 请求转发到 http://api.example.com
浏览器只看到 localhost 域名,永远只看到同源请求,所以跨域问题被绕开。
这就是为什么在开发环境不会出现跨域问题的原因,使用 Next.js、Vite、Webpack DevServer 等开发环境时,通常会配置 proxy 或 rewrite,把请求转发到后端服务器。脚手架自动处理了。
如何减少浏览器预检次数(提升性能)
设置缓存:Access-Control-Max-Age: 86400,预检结果可以缓存一天。
静态资源为什么不跨域
如图片:<img src="https://image.xxx.com/a.png"> 不会报跨域,因为_浏览器对资源加载策略宽松(只不允许JS访问资源内容)。_例如:
- 加载图片:可以显示,但 JS 不能读 pixel(除非 CORS)
- 加载 script:默认允许执行
- 加载字体:通常需要 CORS
- 加载视频:限制更严格
这些都属于 CSP / CORS / Fetch API 的权限体系。

