HTTP 完全指南(最终篇):CORS 跨域资源共享深度详解

引言

前端开发中最让人头疼的报错之一:

Access to XMLHttpRequest at 'http://api.example.com/user'

from origin 'http://www.example.com' has been blocked by CORS policy:

No 'Access-Control-Allow-Origin' header is present on the requested resource.

这就是跨域问题 。很多开发者的第一反应是"后端加个 Access-Control-Allow-Origin: * 就好了",但为什么加这个就能解决?什么时候该用 *?什么时候不该用?带 Cookie 的跨域请求怎么处理?

本文将彻底讲透 CORS 的原理、分类和解决方案。

第一部分:同源策略

一、什么是同源

两个 URL 同源,必须满足三个条件完全相同

条件 URL1 URL2 是否同源
协议 http:// https:// ❌ 协议不同
域名 www.a.com api.a.com ❌ 子域名不同
端口 :80 :8080 ❌ 端口不同
全部相同 http://a.com:80/a http://a.com:80/b ✅ 同源

同源策略限制的是

  • Cookie、LocalStorage 的读取

  • DOM 的访问

  • AJAX 请求的发送

不受同源策略限制的

  • <script src="..."> 加载 JS

  • <img src="..."> 加载图片

  • <link href="..."> 加载 CSS

  • <a> 链接跳转

  • 表单提交

这就是为什么 JSONP 能跨域------它利用了 <script> 标签不受同源策略限制的"漏洞"。


第二部分:CORS 的分类

浏览器把跨域请求分为两类:简单请求非简单请求

一、简单请求的三个条件(必须同时满足)

1. 请求方法是以下三种之一

  • GET

  • HEAD

  • POST

2. 只包含以下请求头(不能有自定义头):

  • Accept

  • Accept-Language

  • Content-Language

  • Content-Type(仅限三种值)

3. Content-Type 只能是

  • text/plain

  • multipart/form-data

  • application/x-www-form-urlencoded

任何不满足以上条件的就是非简单请求。比如:

  • PUT、DELETE、PATCH 方法

  • 自定义请求头(如 AuthorizationX-Custom-Header

  • Content-Type 是 application/json

二、简单请求的流程

核心头

请求头:Origin: http://www.example.com

响应头:Access-Control-Allow-Origin: http://www.example.com

三、非简单请求(预检请求)

预检请求相关的头

头(请求) 含义
Access-Control-Request-Method 告知真实请求的方法
Access-Control-Request-Headers 告知真实请求的自定义头
头(响应) 含义
Access-Control-Allow-Origin 允许的源
Access-Control-Allow-Methods 允许的方法
Access-Control-Allow-Headers 允许的请求头
Access-Control-Max-Age 预检缓存时间(秒),时间内不发第二次预检

默认情况下,跨域请求不携带 Cookie

一、前端设置

javascript 复制代码
// 原生 XHR
const xhr = new XMLHttpRequest();
xhr.withCredentials = true;  // 关键!

// Fetch
fetch('http://api.example.com/user', {
    credentials: 'include'    // 关键!
});

二、后端设置

javascript 复制代码
响应头:
Access-Control-Allow-Origin: http://www.example.com   ← 不能用 *!
Access-Control-Allow-Credentials: true                ← 必须

两条硬规则

  1. Access-Control-Allow-Origin 不能是 *,必须是具体的源

  2. 必须加 Access-Control-Allow-Credentials: true

第四部分:完整 CORS 响应头速查

响应头 作用 示例
Access-Control-Allow-Origin 允许的源 http://www.example.com*
Access-Control-Allow-Credentials 允许携带 Cookie true
Access-Control-Allow-Methods 允许的 HTTP 方法 GET, POST, PUT, DELETE
Access-Control-Allow-Headers 允许的请求头 Authorization, Content-Type
Access-Control-Expose-Headers 允许 JS 读取的响应头 X-Total-Count
Access-Control-Max-Age 预检缓存时间 86400(24小时)

第五部分:常见跨域解决方案对比

方案 原理 优点 缺点
CORS 服务器加响应头 标准方案,功能完整 需要后端配合
JSONP <script> 标签不受跨域限制 兼容老浏览器 只支持 GET
反向代理 同域下转发请求 彻底避开跨域 需要运维配置
postMessage HTML5 跨文档通信 iframe 间通信 需双方配合
WebSocket 不受同源策略限制 双向通信 需要服务器支持

JSONP 示例

html 复制代码
<script>
function handleResponse(data) {
    console.log(data);
}
</script>
<script src="http://api.example.com/user?callback=handleResponse"></script>
javascript 复制代码
// 服务器返回
handleResponse({"name": "张三", "age": 20});

JSONP 已过时,新项目统一用 CORS

反向代理(开发环境常用)

javascript 复制代码
// vite.config.js
export default {
    server: {
        proxy: {
            '/api': {
                target: 'http://api.example.com',
                changeOrigin: true
            }
        }
    }
};

前端请求 /api/user → 开发服务器转发到 http://api.example.com/api/user → 同源,无跨域问题。


第六部分:面试题

1. Q:什么是同源策略?

A:浏览器安全机制。两个 URL 的协议、域名、端口必须完全相同才算同源。同源策略限制不同源之间的 Cookie 读取、DOM 访问、AJAX 请求。

2. Q:简单请求和非简单请求的区别?

A:简单请求(GET/POST/HEAD + 特定 Content-Type)直接发送,浏览器自动带 Origin 头。非简单请求(PUT/DELETE、自定义头、application/json)先发 OPTIONS 预检请求,服务器允许后才发真实请求。

3. Q:跨域带 Cookie 需要什么配置?

A:前端设置 withCredentials: true;后端设置 Access-Control-Allow-Origin 为具体源(不能用 *)+ Access-Control-Allow-Credentials: true;Cookie 本身需要 SameSite=None; Secure

4. Q:为什么跨域请求的响应被拦截了,但请求实际已发出?

A:浏览器的同源策略只拦截 JS 读取响应,不拦截请求的发送。服务器确实收到了请求并处理了。这是防止恶意网站读取用户数据,但不阻止数据提交。

5. Q:CORS 和 JSONP 选哪个?

A:CORS。JSONP 只支持 GET、有 XSS 风险、已过时。新项目统一用 CORS,需要兼容老 IE 时才考虑 JSONP。


总结

一、CORS 核心流程

二、关键响应头

javascript 复制代码
Access-Control-Allow-Origin: http://www.example.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Max-Age: 86400

三、一句话记忆

同源策略限制跨域 AJAX,CORS 通过服务器返回 Access-Control-Allow-Origin 等响应头来授权跨域访问。简单请求直接带 Origin,非简单请求先发 OPTIONS 预检。带 Cookie 需要前端开 withCredentials + 后端指定具体 Origin 并开 Credentials

相关推荐
liulilittle1 小时前
过冲:拥塞控制的呼吸与盲行
linux·网络·c++·tcp/ip·计算机网络·tcp·通信
兮动人2 小时前
服务器流量监控与性能优化实战
服务器·网络·性能优化·服务器流量监控与性能优化实战
San813_LDD2 小时前
[量化]《浮点数比较的艺术:从内存布局到极致性能优化》
网络·算法
Oll Correct2 小时前
实验三十一:配置DHCP中继代理
网络·笔记
user73263921004782 小时前
借助AI再次理解三次握手和四次挥手
网络协议·面试
茶乡浪子2 小时前
同子网基于IPv4网络静态VXLAN配置示例(下)
运维·网络·数据中心·vxlan·evpn·华为vxlan·华为数据中心网络
abcefg_h3 小时前
HTTP 协议版本演进:从 TCP 连接到 QUIC
网络·网络协议·http
liulilittle3 小时前
拥塞控制:公平性的不可能三角
网络·c++·网络协议·tcp/ip·计算机网络·tcp·通信
ylscode3 小时前
Comodo Internet Security 曝高危零日漏洞 ComoDoS:单个 IPv6 数据包即可触发 Windows 蓝屏死机
网络·安全·安全威胁分析