浏览器同源策略和跨域解决方案
同源策略
两个源的URL在 协议、域名、端口 三个方面完全相同才被认为是同源
跨域
跨域是浏览器的同源策略导致的安全限制问题。当前端应用和后端 API 不在同一个 "源" 时,浏览器会阻止它们之间的直接通信
受同源策略限制的场景
shell
1. AJAX 请求
2. <script> || <iframe> 标签内的内容依然受跨域限制(标签是可以跨域的)
3. Web Workers
4. Web字体
5. 读取非同源的Cookie、LocalStorage等不会限制跨域的场景
shell
标签
1. <script> || <iframe> 标签本身,标签内的内容依然受跨域限制
2. <img>, <video>, <audio> 等媒体标签
3. <link rel="stylesheet"> CSS 文件
4. <object>, <embed>, <applet>
WebSocket 协议
postMessage
document.domain解决跨域的几种方式
方式一:CORS (Cross-Origin Resource Sharing):服务端设置请求头,允许服务器声明哪些源可以访问它的资源 方式二:代理服务器:Nginx反向代理 或者 Node.js中间件代理:利用在服务器上不存在同源策略一说 方式三:JSONP (JSON with Padding):script标签中发送请求,在window.success()函数的回调中接收参数 方式四:开发环境可以通过构建工具的 proxy 代理配置,解决开发环境跨域问题
示例:cors 跨域
- 流程:浏览器发送 OPTIONS 方法的预检请求 --> 服务器响应预检请求 --> 如果预检通过,浏览器发送实际请求 --> 服务器返回实际响应
- 关键请求头
shell
# 客户端设置的请求头
Origin:请求源
Access-Control-Request-Method:实际请求将使用的方法
Access-Control-Request-Headers:实际请求将携带的自定义头部
fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token123'
},
})
# 服务端设置允许的请求头
Access-Control-Allow-Origin:指定允许访问资源的源
Access-Control-Allow-Methods:允许的HTTP方法
Access-Control-Allow-Headers:允许的请求头
Access-Control-Allow-Credentials:是否允许发送Cookie
Access-Control-Max-Age:预检请求的缓存时间
Access-Control-Expose-Headers:允许浏览器访问的响应头
app.use((req, res, next) => {
// 允许所有源访问
res.header('Access-Control-Allow-Origin', '*');
// 或指定特定源
// 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');
// 允许携带凭证(如cookies)
// res.header('Access-Control-Allow-Credentials', 'true');
// 预检请求直接返回200
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}
next();
});注意
- 前后端分离的项目肯定会出现跨域
- 同源策略是浏览器独有的,在服务器上不存在同源策略一说,所以可以使用代理服务器实现跨域
