目录
引言
在现代 Web 开发中,跨域请求已经成为不可避免的一部分。浏览器的同源策略(Same-Origin Policy)虽然提供了基本的安全保障,但也限制了不同域之间的数据交互。为了弥补这一限制,CORS(Cross-Origin Resource Sharing,跨域资源共享)应运而生。CORS 是浏览器的一项安全机制,允许从一个域名(如前端页面的域)发起跨域请求,从而访问其他域名(如后端 API)的资源。通过这一机制,Web 应用可以灵活地访问跨域的资源,同时确保用户数据的安全。
本文将详细介绍 CORS 的工作原理、涉及的 HTTP 头部、跨域请求的不同类型以及如何在前后端开发中正确配置 CORS,帮助开发者更好地理解和解决常见的跨域问题。
一、同源策略(Same-Origin Policy)概述
1.1 同源策略的定义
浏览器的同源策略(Same-Origin Policy)是一种重要的安全机制,用于阻止不同源(域)之间的恶意操作。根据同源策略,网页中的脚本只能访问与其所在网页相同源的资源。源的定义包括三个主要部分:
- 协议(Scheme):如
http://
或https://
; - 主机(Host):如
www.example.com
或api.example.com
; - 端口(Port):如
80
或8080
。
如果请求的协议、主机名或端口号不一致,浏览器将视为跨域请求,默认会阻止这样的访问。例如:
http://example.com
和https://example.com
属于不同来源(协议不同);http://example.com
和http://api.example.com
属于不同来源(主机名不同);http://example.com:80
和http://example.com:8080
属于不同来源(端口不同)。
1.2 同源策略的作用
同源策略的核心目的是保护用户的数据隐私和安全,避免恶意网站通过脚本发起未经授权的请求,从而窃取或篡改用户的数据。例如:
- 一个恶意网站可能试图通过 JavaScript 脚本访问银行网站,获取用户的敏感信息如账户余额或信用卡号码。
- 如果没有同源策略的保护,网站之间的数据交换将可能面临被恶意操控的风险。
二、CORS 的引入与工作原理
由于同源策略对跨域资源共享的限制,前端开发中常常需要访问不同域的资源,比如从
www.example.com
向
api.example.com
请求数据。为了能够安全、灵活地进行跨域通信,CORS(跨域资源共享)机制应运而生。
2.1 CORS(跨域资源共享)的基本概念
CORS(Cross-Origin Resource Sharing) 是一种机制,允许受限的资源在一个域(域A)上被另一个域(域B)请求。CORS 通过在 HTTP 请求中添加额外的头部信息来实现跨域通信,从而解决了浏览器的同源策略限制。
同源策略(Same-Origin Policy)
浏览器的同源策略(Same-Origin Policy)是一种用于防止不同来源的网页互相干扰的机制。它要求,网页中的脚本只能访问与它相同源的资源。换句话说,不同域名、协议或端口的资源访问会被浏览器默认阻止。
同源的定义:
- 相同的协议(http:// 与 https://)
- 相同的主机名(www.example.com 与 example.com)
- 相同的端口号(80与8080)
如果协议、主机名或端口号不相同,则被视为跨域请求。
CORS 的核心思想是,服务器通过在 HTTP 响应头中设置特定字段,来允许或拒绝跨域请求。CORS 并不改变浏览器的同源策略,而是通过配置来放宽限制。
2.2 简单请求与预检请求
根据请求类型,CORS 分为两种情况:简单请求和预检请求。
2.2.1 简单请求(Simple Requests)
简单请求是指那些符合以下条件的跨域请求:
- 请求方法是
GET
、POST
或HEAD
; - 请求头部只包含以下字段之一:
Accept
、Content-Type
(只限application/x-www-form-urlencoded
、multipart/form-data
和text/plain
),Authorization
等常见字段。
对于这种请求,浏览器会直接发送请求到服务器,并且不发送预检请求。
2.2.2 预检请求(Preflight Request)
如果跨域请求方法是
PUT
、
DELETE
、
PATCH
,或者请求中包含自定义的 HTTP 头部(如
X-Custom-Header
),浏览器首先会发送一个
OPTIONS
请求来询问服务器是否允许跨域请求。该请求被称为“预检请求”。服务器需要在响应中包含允许跨域访问的标识,浏览器才会继续发送实际的请求。
2.3 预检请求流程
在进行跨域请求时,浏览器通常会先发送一个预检请求(
OPTIONS
请求)以确定服务器是否允许跨域访问。预检请求的流程如下:
- 浏览器发送
OPTIONS
请求:浏览器向服务器发送一个OPTIONS
请求,询问服务器是否支持跨域请求。 - 服务器响应 CORS 头部信息:服务器根据请求的内容,在响应头中添加 CORS 相关的字段,告知浏览器是否允许跨域请求。
- 判断是否允许跨域请求:浏览器根据服务器返回的 CORS 头部信息,判断是否允许继续发送实际的跨域请求。
- 发送实际请求或报错: - 如果服务器允许,浏览器会继续发送实际请求。- 如果服务器不允许,浏览器会拒绝请求并抛出 CORS 错误。
#mermaid-svg-2efqxlkTNxQXFJMR {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-2efqxlkTNxQXFJMR .error-icon{fill:#552222;}#mermaid-svg-2efqxlkTNxQXFJMR .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2efqxlkTNxQXFJMR .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-2efqxlkTNxQXFJMR .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2efqxlkTNxQXFJMR .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2efqxlkTNxQXFJMR .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2efqxlkTNxQXFJMR .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2efqxlkTNxQXFJMR .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2efqxlkTNxQXFJMR .marker.cross{stroke:#333333;}#mermaid-svg-2efqxlkTNxQXFJMR svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2efqxlkTNxQXFJMR .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2efqxlkTNxQXFJMR .cluster-label text{fill:#333;}#mermaid-svg-2efqxlkTNxQXFJMR .cluster-label span{color:#333;}#mermaid-svg-2efqxlkTNxQXFJMR .label text,#mermaid-svg-2efqxlkTNxQXFJMR span{fill:#333;color:#333;}#mermaid-svg-2efqxlkTNxQXFJMR .node rect,#mermaid-svg-2efqxlkTNxQXFJMR .node circle,#mermaid-svg-2efqxlkTNxQXFJMR .node ellipse,#mermaid-svg-2efqxlkTNxQXFJMR .node polygon,#mermaid-svg-2efqxlkTNxQXFJMR .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2efqxlkTNxQXFJMR .node .label{text-align:center;}#mermaid-svg-2efqxlkTNxQXFJMR .node.clickable{cursor:pointer;}#mermaid-svg-2efqxlkTNxQXFJMR .arrowheadPath{fill:#333333;}#mermaid-svg-2efqxlkTNxQXFJMR .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2efqxlkTNxQXFJMR .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2efqxlkTNxQXFJMR .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-2efqxlkTNxQXFJMR .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-2efqxlkTNxQXFJMR .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2efqxlkTNxQXFJMR .cluster text{fill:#333;}#mermaid-svg-2efqxlkTNxQXFJMR .cluster span{color:#333;}#mermaid-svg-2efqxlkTNxQXFJMR div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2efqxlkTNxQXFJMR :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-2efqxlkTNxQXFJMR .watermark>*{fill:#fff!important;stroke:none!important;font-size:15px!important;opacity:0.8!important;}#mermaid-svg-2efqxlkTNxQXFJMR .watermark span{fill:#fff!important;stroke:none!important;font-size:15px!important;opacity:0.8!important;}
是
否
CSDN @ 2136
浏览器发送 OPTIONS 请求
服务器响应 CORS 头部信息
是否允许跨域请求?
浏览器发送实际请求
浏览器拒绝请求, 提示 CORS 错误
服务器响应实际请求
浏览器处理并显示响应
CSDN @ 2136
说明:
- 浏览器发送 OPTIONS 请求:浏览器首先发送一个
OPTIONS
请求到服务器,以询问是否允许跨域请求。 - 服务器响应 CORS 头部信息:服务器在响应中包含
Access-Control-Allow-Origin
等 CORS 相关头部,告知浏览器是否允许跨域。 - 判断是否允许跨域请求: - 如果服务器允许跨域,浏览器会发送实际请求。- 如果服务器不允许,浏览器会拒绝请求,并报出 CORS 错误。
- 发送实际请求或拒绝: - 如果允许,浏览器继续发出实际请求。- 如果不允许,浏览器会显示 CORS 错误。
- 服务器响应实际请求:如果跨域请求被允许,服务器会正常响应实际请求。
- 浏览器处理并显示响应:浏览器接收并处理服务器返回的数据,最后展示给用户。
通过上述流程,浏览器能够确保服务器允许跨域请求,从而安全地进行数据交换。
三、CORS 相关 HTTP 头部
CORS 主要依赖服务器端的 HTTP 头部来进行配置。以下是常见的 CORS 相关头部字段及其作用:
Access-Control-Allow-Origin
:指定哪些源(域)可以访问资源。可以是单个源,或者是*
(允许所有源)。Access-Control-Allow-Methods
:指定允许的 HTTP 方法(如GET
,POST
,PUT
,DELETE
等)。Access-Control-Allow-Headers
:指定允许的请求头字段。Access-Control-Allow-Credentials
:指示是否允许发送凭据(如 cookies)到跨域资源。Access-Control-Expose-Headers
:允许客户端访问特定的响应头。Access-Control-Max-Age
:指示预检请求的有效期,即多少秒内无需再次发送预检请求。
3.1
Access-Control-Allow-Origin
- 作用:指定哪些源(域)可以访问该资源。可以是单个域名,也可以是
*
,表示允许所有来源。 - 值: - 单个域名:
Access-Control-Allow-Origin: https://www.example.com
- 允许所有来源:Access-Control-Allow-Origin: *
- 如果允许的来源是动态的,服务器可以根据请求的Origin
动态返回允许的域名。
3.2
Access-Control-Allow-Methods
- 作用:指定允许的 HTTP 请求方法。
- 常见值:
GET, POST, PUT, DELETE, PATCH
3.3
Access-Control-Allow-Headers
- 作用:指定哪些请求头字段可以包含在实际请求中。例如,某些自定义请求头,如
X-Custom-Header
,需要通过这个字段允许。 - 示例:
Access-Control-Allow-Headers: Content-Type, X-Custom-Header
3.4
Access-Control-Allow-Credentials
- 作用:指示是否允许发送凭据(如 cookies)。如果设置为
true
,表示跨域请求中可以发送 cookies。 - 值:
true
或false
。 - 注意:当设置为
true
时,Access-Control-Allow-Origin
不能为*
,必须指定具体的域名。
3.5
Access-Control-Expose-Headers
- 作用:允许浏览器访问指定的响应头。默认情况下,浏览器只会暴露某些标准的响应头,使用该字段可以暴露其他自定义的头部。
- 示例:
Access-Control-Expose-Headers: X-Response-Time
3.6
Access-Control-Max-Age
- 作用:指定预检请求的有效期(单位为秒)。在此期间,浏览器不会再次发送预检请求。
- 示例:
Access-Control-Max-Age: 3600
表示预检请求的结果有效期为 1 小时。
四、跨域请求的类型
4.1 简单请求
- GET、POST、HEAD 方法
- 头部字段限制:只允许常见的头部字段,如
Accept
、Content-Type
、Authorization
等。
4.2 预检请求
- 如果请求方法是
PUT
、DELETE
、PATCH
,或者包含自定义头部字段,浏览器会先发送一个OPTIONS
请求(预检请求)询问服务器是否允许跨域操作。
五、处理跨域问题的常见方式
以下分别展示在前端、Node.js、Python 和 Go 中处理跨域请求的代码示例,并对其进行详细说明。
5.1 前端(JavaScript)处理 CORS
在前端代码中,通常通过设置 **
fetch
** 或 **
XMLHttpRequest
** 的
mode
、
credentials
等选项来控制跨域行为。
5.1.1 使用
fetch
发起跨域请求
fetch('https://example.com/data',{
method:'GET',
headers:{'Content-Type':'application/json',},// 是否允许携带 cookies
credentials:'include',// 'same-origin', 'include', 'omit'}).then(response=>{return response.json();}).then(data=>{
console.log(data);}).catch(error=>{
console.error('Error:', error);});
credentials: 'include'
:允许携带 cookies。如果目标服务器配置了 CORS 头部Access-Control-Allow-Credentials: true
,浏览器才会发送带有 cookies 的跨域请求。
5.1.2 使用
XMLHttpRequest
发起跨域请求
var xhr =newXMLHttpRequest();
xhr.open('GET','https://example.com/data',true);
xhr.withCredentials =true;// 设置是否带上凭证
xhr.setRequestHeader('Content-Type','application/json');
xhr.onreadystatechange=function(){if(xhr.readyState ==4&& xhr.status ==200){
console.log(JSON.parse(xhr.responseText));}};
xhr.send();
5.2 Node.js 中处理 CORS
在 Node.js 中,处理 CORS 最常见的方式是使用
cors
中间件,它能简化 CORS 相关的配置。
5.2.1 使用
cors
中间件
首先,需要安装
cors
:
npminstall cors
然后在代码中引入并使用它:
const express =require('express');const cors =require('cors');const app =express();// 使用 cors 中间件
app.use(cors({
origin:'https://your-frontend-domain.com',// 允许的来源
methods:['GET','POST','PUT','DELETE'],
allowedHeaders:['Content-Type','Authorization'],
credentials:true// 允许携带凭证}));
app.get('/data',(req, res)=>{
res.json({ message:'Hello World'});});
app.listen(3000,()=>{
console.log('Server running on port 3000');});
5.2.2 使用自定义 CORS 头部
如果不使用
cors
中间件,可以手动添加 CORS 头部:
const express =require('express');const app =express();
app.use((req, res, next)=>{
res.header('Access-Control-Allow-Origin','https://your-frontend-domain.com');// 允许的源
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');next();});
app.get('/data',(req, res)=>{
res.json({ message:'Hello World'});});
app.listen(3000,()=>{
console.log('Server running on port 3000');});
5.3 Python 中处理 CORS
在 Python 中,可以使用
Flask-CORS
扩展来处理 CORS。
5.3.1 安装
Flask-CORS
pip install flask-cors
5.3.2 配置 CORS
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app, origins="https://your-frontend-domain.com", supports_credentials=True)@app.route("/data")defdata():return{"message":"Hello World"}if __name__ =="__main__":
app.run(port=5000)
5.4 Go 语言中处理 CORS
在 Go 中,可以通过
gorilla/handlers
或
net/http
来处理 CORS。
5.4.1 使用
gorilla/handlers
首先安装
gorilla/handlers
:
go get github.com/gorilla/handlers
然后配置 CORS:
package main
import("fmt""github.com/gorilla/mux""github.com/gorilla/handlers""net/http")funcmain(){
r := mux.NewRouter()
r.HandleFunc("/data",func(w http.ResponseWriter, r *http.Request){
w.Write([]byte(`{"message": "Hello World"}`))}).Methods("GET")// 配置 CORS
headersOk := handlers.AllowedHeaders([]string{"X-Requested-With","Content-Type","Authorization"})
originsOk := handlers.AllowedOrigins([]string{"https://your-frontend-domain.com"})
methodsOk := handlers.AllowedMethods([]string{"GET","POST","PUT","DELETE"})// 启动服务器
http.ListenAndServe(":3000", handlers.CORS(originsOk, headersOk, methodsOk)(r))}
六、CORS 处理流程图
#mermaid-svg-xOwLKhcs74yHPFBk {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-xOwLKhcs74yHPFBk .error-icon{fill:#552222;}#mermaid-svg-xOwLKhcs74yHPFBk .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-xOwLKhcs74yHPFBk .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-xOwLKhcs74yHPFBk .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-xOwLKhcs74yHPFBk .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-xOwLKhcs74yHPFBk .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-xOwLKhcs74yHPFBk .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-xOwLKhcs74yHPFBk .marker{fill:#333333;stroke:#333333;}#mermaid-svg-xOwLKhcs74yHPFBk .marker.cross{stroke:#333333;}#mermaid-svg-xOwLKhcs74yHPFBk svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-xOwLKhcs74yHPFBk .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-xOwLKhcs74yHPFBk .cluster-label text{fill:#333;}#mermaid-svg-xOwLKhcs74yHPFBk .cluster-label span{color:#333;}#mermaid-svg-xOwLKhcs74yHPFBk .label text,#mermaid-svg-xOwLKhcs74yHPFBk span{fill:#333;color:#333;}#mermaid-svg-xOwLKhcs74yHPFBk .node rect,#mermaid-svg-xOwLKhcs74yHPFBk .node circle,#mermaid-svg-xOwLKhcs74yHPFBk .node ellipse,#mermaid-svg-xOwLKhcs74yHPFBk .node polygon,#mermaid-svg-xOwLKhcs74yHPFBk .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-xOwLKhcs74yHPFBk .node .label{text-align:center;}#mermaid-svg-xOwLKhcs74yHPFBk .node.clickable{cursor:pointer;}#mermaid-svg-xOwLKhcs74yHPFBk .arrowheadPath{fill:#333333;}#mermaid-svg-xOwLKhcs74yHPFBk .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-xOwLKhcs74yHPFBk .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-xOwLKhcs74yHPFBk .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-xOwLKhcs74yHPFBk .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-xOwLKhcs74yHPFBk .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-xOwLKhcs74yHPFBk .cluster text{fill:#333;}#mermaid-svg-xOwLKhcs74yHPFBk .cluster span{color:#333;}#mermaid-svg-xOwLKhcs74yHPFBk div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-xOwLKhcs74yHPFBk :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-xOwLKhcs74yHPFBk .watermark>*{fill:#fff!important;stroke:none!important;font-size:15px!important;opacity:0.8!important;}#mermaid-svg-xOwLKhcs74yHPFBk .watermark span{fill:#fff!important;stroke:none!important;font-size:15px!important;opacity:0.8!important;}
是
否
成功
失败
CSDN @ 2136
前端请求资源
浏览器发送请求
浏览器检测是否跨域
是否跨域?
发送预检请求 OPTIONS
直接发送请求
服务器检查预检请求并返回 CORS 响应头
浏览器继续发送实际请求
浏览器阻止实际请求并报告错误
服务器处理请求并返回数据
浏览器接受响应
渲染页面
浏览器反馈 CORS 错误
CSDN @ 2136
解释:
- 前端请求资源:前端应用(例如一个网页)发出请求,可能会向不同的域、协议或端口请求资源,导致跨域。
- 浏览器发送请求:浏览器会发起 HTTP 请求,向服务器请求所需资源。
- 浏览器检测是否跨域:浏览器根据请求的目标 URL 判断请求是否跨域。如果目标 URL 与当前网页 URL 的域、协议或端口不同,则认为是跨域请求。
- 是否跨域:这是判断跨域请求与否的关键节点。如果请求和当前页面的源不同,则会触发 CORS 机制。- 是跨域:浏览器会发送一个预检请求(Preflight Request)。这是一个 HTTP 请求,用于询问目标服务器是否允许跨域访问,通常是一个
OPTIONS
请求。- 否跨域:如果请求没有跨域,浏览器会直接发送请求,不经过预检过程。 - 发送预检请求(OPTIONS):如果是跨域请求,浏览器会先发送一个
OPTIONS
请求,询问服务器是否允许跨域操作。 - 服务器检查预检请求并返回 CORS 响应头:服务器收到预检请求后,会根据 CORS 配置返回相应的 CORS 头部信息,如
Access-Control-Allow-Origin
和其他相关字段。如果服务器允许该请求,浏览器继续发送实际的请求。 - 服务器处理请求并返回数据:如果预检请求成功,浏览器会发出实际的跨域请求。服务器处理请求并返回数据。
- 浏览器接受响应:浏览器接收到响应后,会检查 CORS 头部,确认是否允许访问资源。如果允许,则进行页面渲染;如果不允许,则阻止该请求。
- 渲染页面:如果响应没有问题,浏览器会将数据渲染到页面上,展示给用户。
- 浏览器反馈 CORS 错误:如果预检请求失败,或者响应头中缺少必要的 CORS 信息,浏览器会终止请求并提示 CORS 错误。
七、CORS 常见问题
7.1
Access-Control-Allow-Origin
设置问题
No ‘Access-Control-Allow-Origin’ header is present on the requested resource:表示响应中缺少
Access-Control-Allow-Origin
头部。
描述:
-
Access-Control-Allow-Origin
是 CORS 头部中的关键字段,用来指定允许跨域访问的来源(即允许哪些域名访问资源)。如果响应中没有该字段或该字段的值不匹配请求的来源,浏览器会阻止跨域请求。报错为:
No ‘Access-Control-Allow-Origin’ header is present on the requested resource。
解决方案:
- 服务器可以通过返回该头部来明确哪些域名被允许跨域访问。可以指定单一域名(如
https://example.com
),或者使用通配符*
允许所有域名访问,但通配符不能与带凭证的请求(如 cookies 或Authorization
头部)一起使用,也不能与credentials: 'include'
一起使用。 - 如果多个域名都需要访问,服务器可以动态判断请求来源,并根据来源返回不同的
Access-Control-Allow-Origin
值。
示例:
Access-Control-Allow-Origin: https://example.com
- 如果允许所有域访问:
Access-Control-Allow-Origin:*
注意:
- 通配符
*
不能与带凭证的请求(例如cookies
、Authorization
)一起使用。如果请求需要凭证,服务器必须指定明确的来源(域名)。即Access-Control-Allow-Origin
必须设置为明确的域名,而不能使用*
。
7.2. 预检请求失败
描述:
- 对于某些复杂的请求(如
PUT
、DELETE
,或包含自定义头部的请求),浏览器会首先发送一个OPTIONS
预检请求,以确认服务器是否接受跨域请求。如果服务器没有正确响应或缺少必需的 CORS 头部,实际请求会被浏览器阻止。报错为:CORS policy: Response to preflight request doesn’t pass access control check。
解决方案:
- 服务器需要正确处理
OPTIONS
请求,并返回适当的 CORS 响应头。常见的响应头包括: Access-Control-Allow-Origin
Access-Control-Allow-Methods
(指定允许的 HTTP 方法,如GET
,POST
,PUT
,DELETE
等)Access-Control-Allow-Headers
(列出允许的自定义头部)
示例:
Access-Control-Allow-Origin:*
Access-Control-Allow-Methods:GET,POST,PUT
Access-Control-Allow-Headers: Content-Type, Authorization
7.3 带凭证的请求问题
描述:
- 当浏览器在请求中包含凭证(如
cookies
或Authorization
头部)时,CORS 请求需要显式的配置来允许凭证一起发送。如果服务器没有设置Access-Control-Allow-Credentials
,浏览器会拒绝携带凭证的请求。可能出现以下错误:Credential is not supported if the CORS header ‘Access-Control-Allow-Origin’ is ‘*’。
解决方案:
- 当浏览器携带凭证(如 cookies 或
Authorization
)发起跨域请求时,服务器需要在响应中设置Access-Control-Allow-Credentials: true
,并且Access-Control-Allow-Origin
不能使用通配符(*
),必须指定明确的域名。
示例:
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials:true
- 如果服务器允许携带
cookies
和其他凭证,但未正确配置Access-Control-Allow-Credentials
,浏览器将拒绝请求。
常见错误:
No 'Access-Control-Allow-Origin' header is present on the requested resource
:这通常意味着服务器没有正确设置Access-Control-Allow-Origin
头部。
7.4 跨域请求的缓存问题
描述:
- 浏览器可能会缓存跨域请求的响应。如果 CORS 响应头设置不当,缓存可能导致不必要的跨域问题。
解决方案:
- 服务器可以通过设置
Cache-Control
头部,控制缓存策略。例如,可以禁用缓存:
Cache-Control: no-store
示例:
Cache-Control: no-cache
Access-Control-Allow-Origin: https://example.com
- 如果需要缓存响应,可以使用
no-cache
,但仍需要确保正确设置 CORS 头部。
7.5 使用代理解决跨域
描述:
- 如果由于 CORS 设置问题而无法直接访问资源,可以通过设置一个代理服务器来转发请求,从而绕过跨域限制。代理服务器会代表客户端发起请求,并返回响应数据。
解决方案:
- 前端可以将请求发送到与页面同域的代理服务器,由代理服务器向目标服务器发起请求,再将响应返回给前端。
优点:
- 这种方式可以避免浏览器的 CORS 限制,但增加了额外的服务器端负担。
总结
CORS 是一种重要的浏览器安全机制,解决了不同源之间资源共享的问题。无论是在前端使用 fetch 或 XMLHttpRequest 发起请求,还是在后端使用中间件或手动设置响应头部,正确的 CORS 配置对于确保跨域请求的顺利进行至关重要。通过合理配置 CORS 相关头部,开发者可以有效避免常见的跨域问题,如头部设置不正确、预检请求失败、带凭证的请求问题等。
掌握 CORS 的核心原理与配置方法,不仅能帮助开发者顺利实现跨域资源共享,还能提高 Web 应用的安全性和用户体验。如果你在开发过程中遇到任何 CORS 配置上的挑战,随时可以寻求更多的帮助和解决方案。
版权归原作者 丶2136 所有, 如有侵权,请联系我们删除。