0.写在最前
啊😭!在我大一学习前端,刚入门的时候,尝试着用jquery做一些小项目,这个东西困扰了我一个寒假!!!!当时没有跨域这个概念,于是乎就开始疯狂的百度。。。。为了不拖进度,把一个前后端分离的项目被逼成了不分离,后来还好,在开学前夕顺利解决,把不分离的“不”字去掉了,并也按时完成了项目!!!
(拖了一个月左右应该也叫按时完成吧,不管了,先奖励自己一个🍗~)
跨域问题真的成了我一段时间的心里阴影,后来一谈到跨域,心里贼怕!
最近复习网络部分,刷到了跨域的知识点,于是结合自己毕生所学(加上搜集的一丢资料),总结了一些关于跨域的知识。
1. 什么是跨域?
先举个栗子🌰,我博客的网址是:https://blog.wangez.site:8080
最前面的https叫做协议,随后的blog.wangez.site叫做域名,最后的8080叫做端口号
(注:真实的博客网址不带8080, 我的博客,都说了是举个栗子🌰,不会有人当真了吧!!!)。
当前页面中的某个接口请求的地址和当前页面的地址如果协议、域名、端口其中有一项不同,就说该接口跨域了
2. 为什么有跨域?
浏览器为了保证网页的安全,出的同源协议策略
这部分以下摘录自MDN,想详细了解这部分可以去 MDN]( https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy))上看看。
同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。
如果两个 URL 的 protocol、port (en-US) (如果有指定的话)和 host 都相同的话,则这两个 URL 是同源。这个方案也被称为“协议/主机/端口元组”,或者直接是 “元组”。(“元组” 是指一组项目构成的整体,双重/三重/四重/五重/等的通用形式)。
下表给出了与 URL http://store.company.com/dir/page.html
的源进行对比的示例:
URL | 结果 | 原因 |
---|---|---|
http://store.company.com/dir2/other.html |
同源 | 只有路径不同 |
http://store.company.com/dir/inner/another.html |
同源 | 只有路径不同 |
https://store.company.com/secure.html |
失败 | 协议不同 |
http://store.company.com:81/dir/etc.html |
失败 | 端口不同 ( http:// 默认端口是80) |
http://news.company.com/dir/other.html |
失败 | 主机不同 |
3. 跨域报错
当我们测接口的时候,看见数据并没有如约而至,打开我们万能的浏览器控制台,看见了这个报错,不要犹豫,就是遇见了跨域问题!
4. 跨域解决办法
4.1 cors
这是我目前写项目最常用的一种解决办法,也是当下最流行的方案,通过设置后端,来解决跨域,简单快捷
传说中的后端跨域!
res.setHeader('Access-Control-Allow-Origin', '*'); // 允许跨域的源地址是什么,可以设置为*,也可以设成你的源地址
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); // 设置返回数据类型
res.setHeader("Access-Control-Allow-Methods", "GET, PUT, OPTIONS, POST"); // 控制哪种请求是可以跨域的
res.setHeader("Access-Control-Allow-Credentials", true); // 跨域的时候是否携带cookie
4.2 jsonp
利用的原理是script标签可以跨域请求资源,将回调函数作为参数拼接在url中
传说中的前端跨域!但是需要后端的小伙伴们来配合我们一下哦🙄
后端收到请求,调用该回调函数,并将数据作为参数返回去,注意设置响应头返回文档类型,应该设置成javascript
res.setHeader('content-type', 'application/javascript') // 要注意不要忘了设置这个 ,否则会出错误!
<script>
function JsonpCallback(data) {
// 在这里处理后端返回来的data数据
console.log(data);
}
</script>
<script src="http://127.0.0.1:12345/jsonp/callback=JsonpCallback"></script>
4.3 postmessage
这个是我没听说过的一种方法,它是利用html5的api进行的,具有特定的使用场景。
使用场景:一个页面中嵌入另一个iframe页面,
在主页面中使用postmessage发送数据,在iframe页面中用监听器接收数据
// 主页面
iFrame.onload = function () {
iFrame.contentWindow.postMessage({ msg: 'MessageFromIndexPage' }, '\*');
}
// iframe页面
window.addEventListener("message", function (event) {
console.log('这里是接收到来自父页面的消息,消息内容在event.data属性中', event)
}, false)
4.4 其他方法:node中间件、nginx反向代理、websocket等
主要是因为同源策略是浏览器的限制,服务器和服务器之间没有限制
这次我们举个菠萝🍍,小红想要小绿的新玩具 (发出接口请求),但是小绿不给他 (同源策略),于是小红去找了小兰,对小兰说,我想要小绿的新玩具 (准备去搞中间件进行转发或者做代理了),小兰去跟小绿要来了新玩具 (拿到了想要的数据,说明方法成功),并将新玩具交给了小红 (解决了跨域)。
在这里面我只接触过node中间件跟nginx反向代理,也不算很深入的了解,所以就先不献丑啦,等日后学有所成再来填上这个坑!
5.最后
跨域是很常见的一个问题,也是出现在面试问题中频率比较高的问题,希望每个小伙伴们在遇到这个问题的时候都能顺利解决。虽然我们现在写项目的时候,框架中大都为我们配置了代理(Vue的proxyTable代理等),但是我想了解其根源对于我们的自我提高是非常有帮助的!