什么是跨域
简单的理解就是因为javascript同源策略的限制
同源:
- 协议相同
- 域名相同
- 端口相同
举例来说,http://www.example.com/dir/page.html
这个网址,协议是http://
,域名是www.example.com
,端口是80
(默认端口可以省略)
不同域条件
先看看域名的组成:
同源政策的目的
同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。
设想这样一种情况:A网站是一家银行,用户登录以后,又去浏览其他网站。如果其他网站可以读取A网站的 Cookie,会发生什么?
很显然,如果 Cookie 包含隐私(比如存款总额),这些信息就会泄漏。更可怕的是,Cookie 往往用来保存用户的登录状态,如果用户没有退出登录,其他网站就可以冒充用户,为所欲为。因为浏览器同时还规定,提交表单不受同源政策的限制。
由此可见,"同源政策"是必需的,否则 Cookie 可以共享,互联网就毫无安全可言了。
同源政策的限制范围
随着互联网的发展,"同源政策"越来越严格。目前,如果非同源,共有三种行为受到限制。
(1) Cookie、LocalStorage 和 IndexDB 无法读取。
(2) DOM 无法获得。
(3) AJAX 请求不能发送。
跨域解决
jsonp(方法一)
jsonp
利用的是script
标签来实现(毕竟script
不存在跨域问题),但是不能自定义修改header头部信息- 只支持
GET
请求,不支持POST
请求,一般在URL
中传入一个callback
的参数,用来调用函数
function getJSON(url,fn){
// 创建 script标签
var oScript = document.createElement('script');
oScript.src = url;
document.body.appendChild(oScript);
var reg = /callback=([^&]+)/;
var fnName = url.match(reg)[1];
// 挂载window
window[fnName] = fn; // 函数在服务器端 执行
oScript.onload = function(){
document.body.removeChild(oScript);
delete(window[fnName]);
}
}
可以通过动态创建script标签,再请求一个接口地址
原生js
var script = document.createElement('script');
script.type = 'text/javascript';
// 传参并指定回调执行函数为onBack
script.src = 'http://www.demo2.com:8080/login?user=admin&callback=onBack';
document.head.appendChild(script);
// 回调执行函数
function onBack(res) {
alert(JSON.stringify(res));
}
vue中使用vue-jsonp插件实现跨域
this.$jsonp('http://xxx' , params).then((res)=>{
console.log(res)
})
Jsonp(JSON with Padding) 是 json 的一种"使用模式",可以让网页从别的域名(网站)那获取资料,即跨域读取数据。
为什么我们从不同的域(网站)访问数据需要一个特殊的技术( JSONP )呢?这是因为同源策略。
CORS(方法二)
这个方法既可以实现post
又可以实现 get
请求
CORS 是一个 W3C 标准,全称是“跨域资源共享”(Cross-origin resource sharing)。它允许浏览器向跨域的服务器,发出
XMLHttpRequest
请求,从而克服了AJAX只能同源使用的限制。
CORS需要浏览器和服务器同时支持,才可以实现跨域请求,目前几乎所有浏览器都支持CORS,IE则不能低于IE10。CORS的整个过程都由浏览器自动完成,前端无需做任何设置,跟平时发送ajax请求并无差异。so,实现CORS的关键在于服务器,只要服务器实现CORS接口,就可以实现跨域通信。
基本思想
:
使用
自定义的HTTP头部
让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是 应该失败。
在php
页面添加一下代码:
header("Access-Control-Allow-Origin:*");
header("Access-Control-Allow-Methods","GET,POST");
补充一下
关于对 浏览器检测是否支持 CORS
function createCORS(fn,url){
var xhr = new XMLHttpRequest();
if('withCredentials' in xhr){
xhr.open(fn,url,true);
}else if(typeof XDomainRequest() != 'undefined'){
cxhr = new XDomainRequest();
cxhr.open(fn,url);
}
}
方法三:WebSocket(想要实现websocket连接,需要有服务器的支持。通信的一个方式 )
Websocket是一个持久化的协议,相对于HTTP这种非持久的协议来说。
web sockets是一种浏览器的API,它的目标是在一个单独的持久连接上提供全双工、双向通信。(同源策略对web sockets不适用)
使用websocket可以在服务器与客户端之间建立一个非http的双向连接,这个连接是实时的也是永久的,除非被显示关闭。服务器可以随时将消息推送到客户端。
web sockets原理:在JS创建了web socket之后,会有一个HTTP请求发送到浏览器以发起连接。取得服务器响应后,建立的连接会使用HTTP升级从HTTP协议交换为web sockt协议。
只有在支持web socket协议的服务器上才能正常工作。
<script>
// 服务器端连接地址为ws:127.0.0.1:8888/imserver/{userId} ,在这里userId是为了区分不同用户的,即可以多用户与服务器进行长连接,消息推送的时候需要指定userId来确定把消息传递给谁
//1.建立与服务器之间的长连接 id 1
var ws = new WebSocket('ws://47.107.65.238:8888/imserver/1')
//2.连接成功后的回调函数
ws.onopen = function(e){
console.log(e)
ws.send('我是客户端') //向服务端发送数据
}
//3.收到服务器消息的回调函数
ws.onmessage = function(e){
console.log(e.data)//看到服务器发送的信息返回
}
ws.onclose = function(){} //连接失败
ws.onerror = function(){} //关闭连接
</script>
方案四:vue开发模式时在webpack中【也就是vue.config.js文件】配置devServe的proxy(代理)
devServer: {
proxy:{ // 处理跨域问题
'/test':{
target:'https://interface.sina.cn', // 需要代理的第三方接口地址
changeOrigin:true, // 开启虚拟服务 跨域
pathRewrite:{ // 路径重写
'^/test':'' 代替target里面的地址
}
}
},
}