一、为什么会出现跨域问题
出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能不能使用。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)
当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不一同,即跨域:
当前页面url | 被请求页面url | 是否跨域 | 原因 |
http://www.a.com | http:www.a.con/index.html | 没有跨域 | 同源(协议、域名、端口相同) |
http://www.a.com | https://www.a.com | 跨域 | 协议不同 |
http://www.a.com | http:www.b.com | 跨域 | 主域名不同 |
http://www.a.com | http://org.a.com | 跨域 | 子域名不同 |
http://www.a.com:8080 | http://www.a.com:8081 | 跨域 | 端口号不同 |
二、同源策略的限制
浏览器同源策略(Same-Origin Policy)是一种基于安全考虑的限制,它的主要作用是防止一个网站访问另一个不同来源的网站的数据。同源策略限制了从一个源加载的文档或脚本如何与来自另一个源的资源进行交互,即一个源的 JavaScript 脚本只能读取同一源的数据,而不能读取其他源的数据。
同源策略主要限制以下几个方面:
1、Cookie、LocalStorage 和 IndexDB 等存储器:浏览器只允许网页访问自身网站的 Cookie、LocalStorage 和 IndexDB 等存储器,不能访问其他网站的存储器。
2、Ajax 请求:XHR(XMLHttpRequest)对象只能访问同一域下的资源,不能访问其他域的资源。
3、DOM 访问:JavaScript 脚本只能访问同一域下的 DOM 对象,不能访问其他域的 DOM 对象。
4、Frame 和 iframe:包含不同源页面的 Frame 和 iframe 也受到同源策略的限制。
需要注意的是,同源策略只限制浏览器端的交互,而不限制服务器端的交互。因此,服务器端可以自由地访问和传输不同源的数据。
三、跨域解决方法
3.1、设置document.domain
因为浏览器是通过document.domain属性来检查两个页面是否同源,因此只要通过设置相同的document.domain,两个页面就可以共享Cookie。(此方案仅限主域相同,子域不同的跨域应用场景。)
https://www.jb51.net/web/578404.html
需要两个页面都加上
3.2、window.postMessage()
页面和其打开的新窗口的数据传递、多窗口之间消息传递、页面与嵌套的iframe消息传递,上面三个场景的跨域数据传递
// 父窗口打开一个子窗口
var openWindow = window.open('http://test2.com', 'title');
// 父窗口向子窗口发消息(第一个参数代表发送的内容,第二个参数代表接收消息窗口的url)
openWindow.postMessage('Nice to meet you!', 'http://test2.com');
调用message事件,监听对方发送的消息
// 监听 message 消息
window.addEventListener('message', function (e) {
console.log(e.source); // e.source 发送消息的窗口
console.log(e.origin); // e.origin 消息发向的网址
console.log(e.data); // e.data 发送的消息
},false);
3.3、JSONP(json with padding)
JSONP 是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,兼容性好(兼容低版本IE),缺点是只支持get请求,不支持post请求。
核心思想:网页通过添加一个<script>元素,向服务器请求 JSON 数据,服务器收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来。
ts使用jsonp:yarn add @types/jsonp
举例:jsonp调用360接口
https://www.csdn.net/tags/NtDakg5sNjA3NDAtYmxvZwO0O0OO0O0O.html
举例:jsonp调用百度接口
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
*{
margin:0;
padding: 0;
}
body{
padding: 50px;
}
input{
width: 300px;
}
ul{
width: 300px;
border: 1px solid #FF69B4;
display: none;
}
li{
list-style: none;
}
li a:hover{
color: hotpink;
}
</style>
</head>
<body>
<input type="text" id="q" />
<ul id="ul1"></ul>
<script type="text/javascript">
function doJson(data){
var oUl=document.getElementById('ul1')
var html='';
if(data.s.length){
oUl.style.display = 'block';
for(var i=0;i<data.s.length;i++){
html+='<li><a href="https://www.baidu.com/s?&wd='+data.s[i]+'">'+data.s[i]+'</a></li>'
}
oUl.innerHTML=html;
}else{
oUl.style.display='none'
}
}
window.onload=function(){
var oQ=document.getElementById('q')
var oUl=document.getElementById('ul1')
oQ.onkeyup=function(){
if(this.value !=""){
var oScript=document.createElement('script')
oScript.src='https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd='+this.value+'&cb=doJson'
document.body.appendChild(oScript)
}else{
oUl.style.display='none'
}
}
}
</script>
</body>
</html>
3.4、CORS
CORS 是跨域资源分享(Cross-Origin Resource Sharing)的缩写。它是 W3C 标准,属于跨源 AJAX 请求的根本解决方法。
1、普通跨域请求:只需服务器端设置Access-Control-Allow-Origin
2、带cookie跨域请求:前后端都需要进行设置
3.5、webpack本地代理
proxy: {
'/api/v1': {
target: "http://xx.x.x.xxx:8080",
pathRewrite: {
'^/api/v1': ''
},
secure: false,
changeOrigin: true,
logLevel: "debug"
}
}
3.6、websocket
Websocket 是 HTML5 的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。WebSocket 和 HTTP 都是应用层协议,都基于 TCP 协议。但是 WebSocket 是一种双向通信协议,在建立连接之后,WebSocket 的 服务器与 客户端都能主动向对方发送或接收数据。同时,WebSocket 在建立连接时需要借助 HTTP 协议,连接建立好了之后 client 与 server 之间的双向通信就与 HTTP 无关了。
3.7、Nginx反向代理
Nginx 实现原理类似于 Node 中间件代理,需要你搭建一个中转 nginx 服务器,用于转发请求。
使用 nginx 反向代理实现跨域,是最简单的跨域方式。只需要修改 nginx 的配置即可解决跨域问题,支持所有浏览器,支持 session,不需要修改任何代码,并且不会影响服务器性能。
我们只需要配置nginx,在一个服务器上配置多个前缀来转发http/https请求到多个真实的服务器即可。这样,这个服务器上所有url都是相同的域 名、协议和端口。因此,对于浏览器来说,这些url都是同源的,没有跨域限制。而实际上,这些url实际上由物理服务器提供服务。这些服务器内的 javascript可以跨域调用所有这些服务器上的url。
注意:htpps协议网站不能嵌套http协议的页面
3.8、在nuxt3项目通过接口转发实现跨域。
nuxt3:接口转发,实现跨域_snowball@li的博客-CSDN博客