为什么会产生跨域问题?
因为浏览器为了请求安全而引入的基于同源策略的安全特性。
当页面和请求的协议、主机名或端口不同时,浏览器判定两者不同源,即为跨域请求。需要注意的是跨域是浏览器的限制,服务端并不受此影响。
如上图所示,一个 origin 由协议(Protocol)、主机名(Host)和端口(Port)组成,这三块也是同源策略的判定条件,只有当协议、主机名和端口都相同时,浏览器才判定两者是同源关系,否则即为跨域。
前端常见的跨域解决方案有 JSONP 、CORS、反向代理(Reverse Proxy)等。
1.jsonp:利用html里面的script标签,可以加载一些其他域下的数据
在设计这个script标签的时候就允许在别的源请求脚本,所以就有开发人员利用这个漏洞来进行跨域,就是jsonp
<script >
function getJsonp(res){
console.log(res)
}
</script>
<script src="文件路径?callback=getJsonp" type="text/javascript"></script>
h5的script标签默认text/javascript,正是因为定义了这个类型,请求的内容会被浏览器当作js执行了
jq的ajax 可以直接设置datatype:‘jsonp’,jsonpCallback:“callback”;
html标签<link><script><img><iframe>等都是具有跨域特性的,可以直接访问别的源资源
2.CORS后端配合解决
CORS:跨域资源共享 支持所有的主流浏览器,ie9+也支持
XMLHttpRequest发送请求的时候,如果不同源,需要在 headers{ Origin }属性,是w3c标准,属于跨域ajax请求的根本解决方法
1.普通跨域请求:只需后端(服务器端)设置Access-control-allow-origin,*所有域名端口都可以访问
2.带cookie跨域请求:前后端都需要进行cookie设置
前端设置 根据xhr.withCredentials字段判断是否携带带有cookie
vue本地开发使用的,服务器代理跨域 proxy 本质上也是cors跨域
vue的项目可以设置代理(生产环境无效。解决:.env文件)
通过中间件来实现,浏览器有跨域限制,但是服务器没有跨域限制,所有中间件其实就是服务器(服务器对数据进行了转发而已)
//代理跨域 proxy 本质上也是cors跨域
//vue.config.js
devServer:{
proxy:{
'/api':{
target:'http://www.baidu.com',//设置你调用的接口域名和端号
changeOrigin:true,//跨域
pathRewrite: {
"^/api":'/',//识别api开头的地址,替换/api为/
}
}
}
3.Nginx反向代理
Nginx实现原理类似于Node中间件代理,需要搭建一个中转的nginx服务器,用于转发请求。
使用nginx反向代理实现跨域,是最简单的跨域方式,只需要修改nginx的配置即可以解决跨域问题,支持所有的浏览器,支持session,不需要修改任何代码,并不会影响服务器性能。
我们只需要配置nginx,在一个服务器配饰多个前缀转发http/https请求到多个真实的服务器即可。这样,这个服务器上多有url都是相同的域名,协议和端口。因此,对于浏览器来说,这些url都是同源的,没有跨域限制。而实际上,这些url实际是有屋里服务器提供服务的。这些服务器内的javascript可以跨域调用所有这些服务器上的url
#proxy
server{
#nginx监听所有www.a.com:80端口收到的请求
listen 80;
server_name www.a.com;
location / {
proxy_pass http://www.b.com; #反向代理,后端程序会接受到"http://www.b.com"请求
proxy_cookie_domain www.b.com www.a.com;
index index.html index.html;
add_header Access-Control-Allow-Origin http://www.a.com;
add_header Access-Control-Allow-Credentials true;
}
}
4.H5 window.postMessage跨域 主流浏览器支持 ie需要8+以上
postMessage可以解决
页面和其他打开的新窗口数据传递
多窗口之间消息传递
页面与嵌套的iframe消息传递
上面三个场景的跨域数据传递
//父窗口向子窗口发送消息(第一个参数代表发送内容,第二个参数代表接收消息窗口url)
window.postMessage("字符串","*")
//子窗口调用message事件,监听父窗口发送的消息
window.addEventListener('message',function(res)=>{
console.log(res.data);//发送内容
},false)
5.websocket
websocket 是html5的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是一种跨域的一种解约方案。
websocket和http都是应用层协议,都基于TCP协议。但是webSocket是一种双向通信协议,在建立链接之后,websocket的服务器与客户端能主动向对方发送或接收数据。同时,websocket在建立连接时需要借助http协议,链接建立好了之后client与server之间的双向通信就与http无关了。