解决前端跨域的几种方法 了解跨域出现的原因
解决跨域的几种方法
想要解决跨域 先要知道为什么会出现跨域
跨域:指的是浏览器不能执行其他网站的脚本 它是由浏览器的同源策略造成的 是浏览器对javascript添加的安全限制 同源策略是一种约定 是浏览器核心的安全功能
同源策略会造成以下的影响
-
Cookie、LocalStorage 和 IndexDB 无法读取
-
DOM 和 JS 对象无法获取
-
Ajax请求发送不出去
是否同源主要看一下三个方面:
- 协议是否相同(http https file)
- 主机地址是否相同(www.xxx.com 127.0.0.1)
- 端口(0~65535)(http 默认端口是 80;https 默认端口是 443;MySQL 默认端口 3306)
如果两个 url 的协议、主机地址、端口都相同,那么这两个 url 是同源的,否则就是非同源。
解决跨域的方案主要有以下几种
JSONP
是程序员被迫想出来的解决跨域的方案。
JSONP 方案和 Ajax 没有任何关系
JSONP 方案只支持 GET 请求 不支持post请求
JSONP 没有浏览器兼容问题,任何浏览器都支持。
核心思想:网页通过添加一个<script>元素
,向服务器请求 JSON 数据,服务器收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来。
-
原理
- 客户端利用 script 标签的 src 属性,去请求一个接口,因为 src 属性不受跨域影响。
- 服务端响应一个字符串
- 客户端接收到字符串,然后把它当做 JS 代码运行。
后端接口代码:
app.get("/api/jsonp", (req, res) => {
// res.send('hello');
// res.send('console.log(1234)');
// res.send('abc()')
// res.send('abc(12345)')
// 接收客户端的函数名
let fn = req.query.callback;
let obj = { status: 0, message: "登录成功" };
let str = JSON.stringify(obj);
res.send(fn + `(${str})`);
});
前端代码:
<script>
// 提前准备好一个函数
function xxx(res) {
console.log(res);
}
</script>
<script src="http://localhost:3006/api/jsonp?callback=xxx"></script>
<script src="http://test.com/data.php?callback=dosomething"></script>
// 向服务器test.com发出请求,该请求的查询字符串有一个callback参数,用来指定回调函数的名字
// 处理服务器返回回调函数的数据
<script type="text/javascript">
function dosomething(res){
// 处理获得的数据
console.log(res.data)
}
</script>
jQuery ajax:
$.ajax({
url: 'http://www.test.com:8080/login',
type: 'get',
dataType: 'jsonp', // 请求方式为jsonp
jsonpCallback: "handleCallback", // 自定义回调函数名
data: {}
});
Vue.js
this.$http.jsonp('http://www.domain2.com:8080/login', {
params: {},
jsonp: 'handleCallback'
}).then((res) => {
console.log(res);
})
前端如果使用jquery $.ajax({dataType:‘jsonp’}) 必须制定dataTape选项为jsonp
后端如果使用express name直接调用res.jsonp(数据) 即可
cors方式
- 前端什么也不用做
- 后端需要开启cors
- CORS 是跨域资源分享(Cross-Origin Resource Sharing)的缩写。它是 W3C 标准,属于跨源 AJAX 请求的根本解决方法。
实际上就是在响应头添加允许跨域的源
Access-Control-Allow-Origin: 字段和值(意思就是允许去哪些源地址去请求这个服务器)
vue-cli代理转发
开发环境
浏览器是禁止跨域的,但是服务端不禁止,在本地运行npm run dev等命令时实际上是用node运行了一个服务器,因此proxyTable实际上是将请求发给自己的服务器,再由服务器转发给后台服务器,做了亦曾代理,因为不会出现跨域问题。
-
如果后端jsonp也不弄, cors也不弄, 就给你个接口地址
-
我们可以在本地弄个服务器, 然后用服务器请求后台服务器接口地址
-
但是vuecli脚手架, 启动了一个webpack开发服务器, 它就能做代理转发
-
- 而且前端和这个服务器是同源的都是8080端口
-
-
需要修改webpack开发服务器的配置即可
在前端服务和后端接口服务之间 架设一个中间代理服务,它的地址保持和前端服务一致,那么:
代理服务和前端服务之间由于协议域名端口三者统一不存在跨域问题,可以直接发送请求
代理服务和后端服务之间由于并不经过浏览器没有同源策略的限制,可以直接发送请求
这样,我们就可以通过中间这台服务器做接口转发,在开发环境下解决跨域问题,看起来好像挺复杂,其实vue-cli已经为我们内置了该技术,我们只需要按照要求配置一下即可。
devServer: {
proxy: {
// http://c.m.163.com/nc/article/headline/T1348647853363/0-40.html
'/api': { // 请求相对路径以/api开头的, 才会走这里的配置
target: 'http://c.m.163.com', // 后台接口域名 我们要代理的真实的接口地址
changeOrigin: true, // 改变请求来源(欺骗后台你的请求是从http://c.m.163.com)
pathRewrite: {
'^/api': '' // 因为真实路径中并没有/api这段, 所以要去掉这段才能拼接正确地址转发请求
}
}
}
}
axios请求的代码
axios({
url: '/api/nc/article/headline/T1348647853363/0-40.html'
})
生产环境下
解决办法: 自己用node+express搭建一个本地服务器开启cors 并启动吧自己前端的请求及地址改为这个服务器一起部署到线上
在自己开启的服务器开启cors 请求的是代理服务器 代理服务器把请求转发给真正的接口服务器 服务器之间不存在跨域问题 跨域是浏览器的安全机制