第一章:前端跨域难题的本质与背景
在现代Web开发中,前端应用常常需要与不同源的后端服务进行数据交互。然而,浏览器出于安全考虑实施了同源策略(Same-Origin Policy),这一机制限制了来自不同源的脚本对文档资源的访问,从而引出了“跨域”问题。
同源策略的基本定义
同源要求协议、域名和端口三者完全一致。例如,
https://example.com:8080 与
https://example.com 被视为不同源,因为端口不同。该策略防止恶意文档或脚本从一个源获取其他源的敏感数据。
跨域请求的典型场景
- 前端部署在
http://localhost:3000,后端API运行于 http://localhost:5000 - 生产环境中前端静态资源托管于CDN,而后端服务位于独立服务器
- 微前端架构中多个子应用分别部署在不同子域名下
浏览器的拦截机制
当发起跨域请求时,浏览器会先发送预检请求(Preflight Request),使用
OPTIONS 方法探测服务器是否允许实际请求。该过程由CORS(跨域资源共享)协议控制,需服务器明确响应相关头部信息。
| 响应头 | 作用说明 |
|---|
Access-Control-Allow-Origin | 指定允许访问资源的源,如 * 或具体域名 |
Access-Control-Allow-Methods | 声明允许使用的HTTP方法 |
Access-Control-Allow-Headers | 指定允许携带的自定义请求头 |
// 示例:Express 中设置CORS响应头
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'http://localhost:3000'); // 允许前端源
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
if (req.method === 'OPTIONS') {
res.sendStatus(200); // 预检请求直接返回成功
} else {
next();
}
});
第二章:CORS——现代跨域解决方案的核心机制
2.1 CORS 基本概念与浏览器同源策略解析
浏览器的同源策略(Same-Origin Policy)是Web安全的基石,它限制了一个源(协议+域名+端口)的文档或脚本如何与另一个源的资源进行交互。这一机制有效防止了恶意文档窃取数据。
同源策略的判定规则
以下三个部分必须完全相同才被视为同源:
- 协议(如 https)
- 域名(如 example.com)
- 端口(如 443)
CORS:跨源资源共享机制
CORS(Cross-Origin Resource Sharing)是一种W3C标准,通过HTTP头部字段允许服务器声明哪些外源可访问其资源。例如,后端可设置:
Access-Control-Allow-Origin: https://client.example.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type
上述响应头表示仅允许来自
https://client.example.com 的请求,并支持GET和POST方法及自定义内容类型头。浏览器在收到响应后校验这些字段,决定是否放行响应数据。
2.2 简单请求与预检请求的触发条件深入剖析
在跨域资源共享(CORS)机制中,浏览器根据请求的复杂程度决定是否发送预检请求(Preflight Request)。满足特定条件的请求被视为“简单请求”,可直接发送;否则需先执行 OPTIONS 预检。
简单请求的判定标准
同时满足以下条件的请求无需预检:
- 使用 GET、POST 或 HEAD 方法
- 仅包含安全的首部字段,如 Accept、Accept-Language、Content-Language、Content-Type
- Content-Type 限于 text/plain、multipart/form-data 或 application/x-www-form-urlencoded
- 未使用 ReadableStream 等高级 API
预检请求的触发场景
当请求包含自定义头部或使用 application/json 以外的 Content-Type 时,浏览器将先行发送 OPTIONS 请求。例如:
fetch('https://api.example.com/data', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-Auth-Token': 'abc123'
},
body: JSON.stringify({ name: 'test' })
});
该请求因携带自定义头
X-Auth-Token 而触发预检。服务器必须正确响应 Access-Control-Allow-Origin 和 Access-Control-Allow-Headers,方可继续实际请求。
2.3 服务端如何正确设置响应头实现跨域支持
在开发前后端分离项目时,跨域资源共享(CORS)是常见问题。服务端需通过设置特定的响应头来允许浏览器接受来自不同源的请求。
关键响应头说明
Access-Control-Allow-Origin:指定允许访问资源的源,可设为具体域名或通配符*Access-Control-Allow-Methods:定义允许的HTTP方法,如GET、POST等Access-Control-Allow-Headers:声明允许的自定义请求头字段
Node.js 示例代码
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'https://example.com');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
next();
});
上述中间件为每个响应添加CORS相关头部,确保客户端请求能被正确授权。其中,Origin应尽量避免使用
*以增强安全性,尤其涉及凭证传输时。
2.4 带凭证请求(withCredentials)的实践与安全限制
在跨域请求中,
withCredentials 是一个关键属性,用于指示浏览器是否应在跨域请求中携带凭据(如 Cookie、HTTP 认证等)。
使用场景与代码示例
fetch('https://api.example.com/data', {
method: 'GET',
credentials: 'include'
})
上述代码通过
credentials: 'include' 启用带凭证请求。该设置等效于 XMLHttpRequest 的
withCredentials = true。
安全限制要求
- 目标服务器必须设置
Access-Control-Allow-Origin 为具体域名,不能为 * - 需显式允许凭证:响应头中包含
Access-Control-Allow-Credentials: true - 涉及敏感信息时,必须启用 HTTPS 防止中间人攻击
这些机制共同保障了跨域身份认证的安全性,防止凭证被无意泄露。
2.5 实战:从零搭建一个支持 CORS 的 Node.js 后端接口
在现代 Web 开发中,跨域资源共享(CORS)是前后端分离架构下必须处理的问题。本节将演示如何使用 Express 框架从零构建一个支持 CORS 的 Node.js 接口服务。
初始化项目与依赖安装
首先创建项目目录并初始化 `package.json`,随后安装核心依赖:
npm init -y
npm install express cors
其中,`express` 用于构建 HTTP 服务,`cors` 是官方推荐的中间件,用于灵活配置跨域策略。
启用 CORS 的服务器实现
以下是基础服务代码:
const express = require('express');
const cors = require('cors');
const app = express();
// 启用默认 CORS 策略
app.use(cors());
app.get('/api/data', (req, res) => {
res.json({ message: 'Hello from Node.js with CORS!' });
});
app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
`app.use(cors())` 允许所有来源访问接口;若需限制特定域名,可传入配置对象,如 `{ origin: 'http://trusted-site.com' }`。
响应头分析
启用 CORS 后,响应中自动添加关键头部:
Access-Control-Allow-Origin:指定允许访问的源Access-Control-Allow-Methods:列出允许的 HTTP 方法Access-Control-Allow-Headers:声明允许的请求头字段
第三章:JSONP——古老的跨域技巧及其应用场景
3.1 JSONP 的原理与 script 标签的巧妙利用
JSONP(JSON with Padding)是一种跨域数据交互技术,其核心原理是利用
<script> 标签不受同源策略限制的特性,动态加载来自其他域的 JavaScript 文件。
执行流程解析
客户端通过创建
<script> 标签,请求一个携带回调函数名的 URL:
function handleResponse(data) {
console.log("接收到的数据:", data);
}
const script = document.createElement('script');
script.src = 'https://api.example.com/data?callback=handleResponse';
document.body.appendChild(script);
服务器返回一段 JS 脚本:
handleResponse({"status": "success", "value": 42});
浏览器执行该脚本,调用预定义的回调函数,完成数据传递。
优缺点对比
- 优点:兼容老浏览器,实现简单,无需复杂配置
- 缺点:仅支持 GET 请求,缺乏错误处理机制,存在 XSS 风险
3.2 手动实现一个健壮的 JSONP 请求函数
在跨域请求受限的环境中,JSONP 仍是一种有效的替代方案。通过动态创建 `