网络跨域
什么是跨域
在讲解跨域之前,需要讲解一个重要的安全策略就是同源策略。 其中,源 = 协议 + 域名 + 端口源,**protocol(协议)、domain(域名)、port(端口)三者一致,**才是同源。反之,就是跨域。
同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。
限制范围
Cookie
、LocalStorage
、IndexDB
DOM
获取AJAX
请求不能发送
源 1 | 源 2 | 是否同源 |
---|---|---|
www.baidu.com | www.baidu.com/news | ✅ |
www.baidu.com | www.baidu.com | ❌ |
http://localhost:5000 | http://localhost:7000 | ❌ |
http://localhost:5000 | http://127.0.0.1:5000 | ❌ |
www.baidu.com | baidu.com | ❌ |
跨域解决方法
代理
适用场景:生产环境不跨域,但是开发环境跨域
nginx代理跨域
nginx
可以使用反向代理来实现跨域访问:
server {
listen 80;
server_name local.test;
location /api {
proxy_pass http://localhost:8080;
}
location / {
proxy_pass http://localhost:8000;
}
}
Node中间件代理
app.use(function (req, res, next) { // 此方法就是一个最基本的中间件,它在每次请求之前打印时间
console.log('Time:', Date.now())
next()
})
app.get('/hello', (req, res) => { // "GET /hello" 就是一个路由
res.send('Hello World!')
})
Node正向代理
正向代理主要是在前端项目中设置,在Vite
和Webpack
的项目中都可以通过配置server
的proxy
信息来实现代理。
JSONP
JSONP的做法是:当需要跨域请求时,不使用AJAX,转而生成一个script元素去请求服务器,由于浏览器并不阻止script元素的请求,这样请求可以到达服务器。服务器拿到请求后,响应一段JS代码,这段代码实际上是一个函数调用,调用的是客户端预先生成好的函数,并把浏览器需要的数据作为参数传递到函数中,从而间接的把数据传递给客户端
<script>
var script = document.createElement('script');
script.type = 'text/javascript';
// 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
script.src = 'http://www.domain2.com:8080/login?user=admin&callback=handleCallback';
document.head.appendChild(script);
// 回调执行函数
function handleCallback(res) { alert(JSON.stringify(res)); }
</script>
缺点:JSONP有着明显的缺点,即其只能支持GET请求
CORS(Cross-Origin Resource Sharing)
cors
跨域资源共享是基于http1.1
的一种跨域方案,整体思路是如果浏览器要跨域访问服务器的资源,需要获得服务器的允许。
针对不同的请求,CORS 规定了三种不同的交互模式,分别是:
- 简单请求
- 需要预检的请求
- 附带身份凭证的请求
这三种模式从上到下层层递进,请求可以做的事越来越多,要求也越来越严格。
const cors = require("koa-cors");
app.use(cors());
简单请求
请求方法属于get
、post
、head
三种方法中的一种,请求头仅包含安全字段,如:
Accept
Accept-Language
Content-Language
Content-Type
DPR
Downlink
Save-Data
Viewport-Width
Width
请求头如果包含Content-Type
,仅限下面的值之一:
text/plain
multipart/form-data
application/x-www-form-urlencoded
当满足上述条件时,浏览器判定为简单请求。 当一个请求满足简单请求的条件是,这个请求会被进行如下加工:
- 请求头中添加
origin
字段,告知服务器是哪个源再跨域请求 - 服务器响应头中添加
Access-Control-Allow-Origin
,表示允许该跨域请求
需要预检的请求
如果不是一个简单请求,那么就会进行如下的流程:
- 浏览器发送预检请求,询问服务器是否允许
- 服务器允许
- 浏览器发送真实请求
- 服务器完成真实的响应 在这里就会发送一个预检请求,用来询问服务器对这类请求是否允许,一般是
OPTIONS
请求,且没有请求体,并在请求头中包含后续真是请求的请求方法和请求头信息。如果服务器允许,那么我们就会发送真实的请求。
附带身份凭证的请求
这类请求通常指的是我们的请求携带cookie
作为验证信息,对于一个携带cookie
的请求,如果没有告知服务器,也会被视为跨域解决。
对于需要携带Cookie
的请求,后端跨域只能设置为Access-Control-Allow-Origin 的值为*
,因为只有这样才能正常传递Cookie
。