一、定义:
跨域又名非同源策略请求,同源指的是相同的协议/域名/端口,三者都要一样才叫同源
二、产生跨域的原因
-
服务器拆分(这样一拆分后域名就不同了)
web服务器:处理静态资源,比如为kbs.qq.com data服务器:业务逻辑和数据分析,包含数据管理asdasd.qq.com 图片服务器:image.qq.com
-
调用第三方开源接口,也会产生跨域
三、判断同源和跨域
通过协议、域名、端口三者来判断,只有三者都一样的时候才是同源,其中一项不同就是跨域;
四、跨域方案
1、早期跨域及处理方案(2013年左右)
开发情景:当时代码部署都是部署到同一台服务器上的(同源),但是开发的时候,前端一般都是通过xampp来起一个前端本地的服务,而后端一般给的服务(接口)都是类似于http://api.qq.com这样的真实域名,所以我们这样直接请求数据就相当于跨域了,直接请求是请求不到的;
解决方法:所以当时有一种办法就是通过修改本地host文件,把本地的域名和真实的域名进行关联,这样访问就模拟了同源的效果;
127.0.0.1:3000 http://api.qq.com
2、JSONP
实现原理:
实现原理及思路解析:
首先客户端会创建一个script标签,通过它的src属性来请求后端的一个接口数据,为什么选择script标签呢?因为script标签的不跨域特性,然后同时将本地创建的一个全局函数,通过callback的方式拼参数拼在地址后面,这时服务器接受到了客户端的请求,它会先开始准备要返回给客户端的数据(data,json格式),然后给客户端返回数据,它返回的是一个类似于调用func函数的字符串,将数据拼在函数的()内,然后当客户端接受到了返回数据(一个函数执行式的字符串),通过解析后,相当于直接执行了全局的func函数,这个解析执行操作是浏览器自身操作的,我们不用管,同时也将data传到了这个函数中,从而达到了客户端向服务器请求数据得到返回的这么一个过程;
注意:
1、这个func函数必须是全局函数,不然返回后不能执行;
2、这种jsonp的方式处理跨域,必须得到服务器端的处理,说白了就是,如果服务器端不接收callback,不给你返回这样格式的字符串数据,你前端再怎么搞也没用;
代码实战:
//html文件,引入两个js文件
<!DOCTYPE html>
<html lang="en">
<script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js" ></script>
<script src="./index.js"></script>
<head>
<meta charset="UTF-8">
<title>fetch</title>
</head>
<body>
</body>
</html>
//本地index.js,然后再index.html中引入该js文件和jquery
$.ajax({ // 这里通过jquery的ajax方法来实现jsonp跨域,jquery中的ajax封装了jsonp的功能,只要传dataType:“jsonp”即可
url:'http://127.0.0.1:8001/list',
method:"get",
dataType:"jsonp",
success:(res)=>{
console.log(res)
}
})
//自己写的一个简单web服务
const express = require('express');
const app =express();
app.listen('8001',()=>{
console.log('ok');
});
app.get('/list',(req,res)=>{
const {callback=Function.prototype}=req.query;
const data= {
code: 0,
message: '你好'
};
res.send(`${callback}(${JSON.stringify(data)})`);
});
缺点:
- jsonp这种通过src方式请求的都是资源文件请求,所以有一个明显的问题就是只支持get请求;
- jsonp安全性也不高,url容易被劫持,或者服务器返回一个木马程序,浏览器执行就中毒了;
3、CORS跨域资源共享
客户端:还是正常发起请求(ajax,fetch);
服务端:要设置响应头参数,以及处理options试探性 预请求处理
要设置的参数有如下: 允许的请求源、是否允许携带凭证、允许的请求头、允许的请求方法
注意: 这里有个注意点,允许源这里有两种设置,一种是还有一种是唯一的一个请求地址,当你设置为时说明,此时允许任务地址来访问该资源,但是此时请求就不能携带cookie了,因为浏览器考虑安全性,如果设置为单一地址,此时时可以携带cookie的;
4、http proxy(代理)
简单原理:
在webpack中可以通过安装webpack-dev-server起一个服务,在webpack.config.js配置文件中的devServer属性中配置相关proxy设置,
它的意思就是说,后续只要是以’/'开头的请求,都会前面自动带上target后面的这个域名, 然后配置了changeOrigin:true,这句话的意思就是说webpack-dev-server会起一个中层代理,相当于用node写了一个中间件,相当于我们客户端的请求会先到这个中间件,中间件中帮我们进行了跨域请求处理,然后把跨域处理后的数据再返回给客户端;
5、Ngnix反向代理=》不需要前端做什么,了解
6、postMessage方式
概述:
就是通过window.postMessage发送消息,然后通过onMessage方法接受消息,本地页面之间的数据传递,同理换成客户端和服务器之间就相当于也是一种解决跨域的方式;
A页面代码:
B页面代码:
7、socket.io(websocket协议跨域)
客户端:
服务端: