跨域
跨域与 CORS
1) 什么是跨域
浏览器判断“是否同源/是否跨域(跨源)”只看 协议 + 域名 + 端口(scheme/host/port)。三者任意一个不同,就是跨域。
http://localhost:8001→http://localhost:8002:跨域(端口不同)http://a.com→https://a.com:跨域(协议不同)http://a.com→http://b.com:跨域(域名不同)
注意:path 不参与跨域判断。
(同源/CORS 概览)https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
2) 请求头是什么
HTTP 请求由「请求行 + 请求头(headers) + 空行 + 可选正文(body)」组成。
- 请求头:一堆
Key: Value,描述这次请求的“元信息/上下文”,比如:Host:要访问哪个站点(虚拟主机选择相关)Origin:浏览器自动带的“发起请求的源”(跨域时关键)Accept:期望响应的数据类型Content-Type:请求 body 的格式(POST/PUT 等常见)Authorization:认证信息(常触发预检)
3) CORS 把跨域请求分为两类
核心区别:是否需要 preflight(预检 OPTIONS)。
A. 简单请求(simple request)
跨域情况下满足条件 → 浏览器 直接发送真正请求,不先发 OPTIONS。
简单请求需要同时满足:
- 方法是:
GET/HEAD/POST - 你在代码里手动设置的请求头属于“安全白名单”(不展开死背,记住:
Authorization、自定义X-*往往会让它变非简单) - 若是
POST,Content-Type只能是以下三种之一:application/x-www-form-urlencodedmultipart/form-datatext/plain
(Simple requests 条件)https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests
简单请求的流程
- 浏览器发送真正请求(带
Origin)到跨域服务器 - 服务器返回响应
- 浏览器检查响应里是否允许该源读取结果:
- 看
Access-Control-Allow-Origin - 若允许 → JS 能读到响应
- 若不允许/缺失 → 请求可能已到后端,但浏览器不让 JS 读取响应(控制台报 CORS)
- 看
重要纠错:Access-Control-Allow-Origin 的值只能是:
*或者 一个 origin(协议+域名+端口),比如http://localhost:8001
不能带 path https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
B. 非简单请求(preflighted request)
只要不满足简单请求条件(常见原因:Content-Type: application/json、带 Authorization、方法是 PUT/DELETE 等),浏览器通常会:
先发预检 OPTIONS(preflight),问服务器“我等会儿这样请求行不行?”
预检请求大概长这样:
OPTIONS /api HTTP/1.1
Origin: http://localhost:8001
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization, content-type
服务器如果同意,需要在 OPTIONS 的响应 里声明允许,例如:
Access-Control-Allow-Origin: http://localhost:8001
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Allow-Headers/Allow-Methods不要求完全一致- 只要它们的允许集合 包含 预检里声明要用的那些即可(集合“超集”覆盖请求即可;从请求角度看就是“请求需求是允许集的子集/真子集”)。
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#preflighted_requests
通过预检后,浏览器才会发真正请求;预检不通过,真正请求通常不会发出。
Reference
Cross-Origin Resource Sharing (CORS)| MDN
Preflight 机制| MDN
HTTP 报文结构
Content-Type