什么是跨域
跨域的产生是因为浏览器的同源策略问题,同源策略是指请求的url地址,必须与浏览器上的url地址的协议名(http,https),域名,端口号(8080)都一样的情况下,才允许访问相同的cookie或是Ajax请求等,如果在不同源的情况下访问这些请求,就称为跨域;
有三个标签支持跨域加载资源:
跨域的方式
vue中实现跨域的方法:
(1) 后端设置允许跨域访问:在生产环境下建议不要设置允许跨域访问或者限制允许跨域的IP
(2) 前端通过代理proxy进行访问后端
配置vue-cli代理访问,比如配置2个请求的后端,分别是
请求http://localhost:4201/adminapi/会代理请求http://localhost:8180/
请求http://localhost:4201/portalapi/会代理请求http://localhost:8185/
因为vue-cli是基于webpack,所以webpack的devServer选项都是支持配置的
module.exports = {
devServer: {
prot: 4201,
proxy: {
"/adminapi": {
// api服务器的地址
target: "http://localhost: 8180",
// 如果是https接口,需要配置这个参数
secure: true,
// 如果是websocket接口,需要配置这个参数
ws: true,
// 是否跨域
changeOrigin: true,
// 重写路径,将"/adminapi"重写为""
pathRewrite: {
"^/adminapi": ""
}
},
"/portalapi": {
target: "http://localhost: 8185",
ws: true,
changeOrigin: true,
pathRewrite: {
"^/portalapi": ""
}
},
}
}
}
proxy代理实现跨域的原理:
vue-cli脚手架工具开发项目时,脚手架工具启动一个本地node服务,这就是开发时预览地址一般是端口号而不是本地文件例如"xx.html"
如果我们的接口地址是/api/user,如果不进行特殊设置,那么ajax请求的地址就是:http://localhost:8888/api/user,
也就是访问的是我们脚手架工具提供的本地的node服务器,如果我们设置了代理,那么本地node服务器收到请求会转发到对应的第三方服务端接口
八股文实现跨域的方法
(1)jsonp:解决跨域请求资源,支持get请求,不支持post请求,ajax直接请求普通文件存在跨域无权限访问的问题,但是在调用js文件又不受跨域影响,比如引入jquery框架,调用图片地址,凡是拥有src属性的标签都可以进行跨域,比如img,scirpt,提供一个script标签,请求页面中的数据,同时传入一个回调函数的名字, 服务端得到名字后执行回调函数,使用远程跨域访问就是将远程服务器数据装入js格式的文件,最后为了方便客户端使用数据形成了jsonp,要点是允许用户传递一个callback参数给服务端
script标签不受策略影响,可以动态生成script去请求数据,但是仅限于Get请求
// 原生实现方法
var script = document.createElement('script');
script.type = 'text/javascript';
// 传参并指定回调执行函数为onBack
script.src = 'http://www.domain2.com:8080/login?user=admin&callback=onBack';
document.head.appendChild(script);
// 回调执行函数
function onBack(res) {
alert(JSON.stringify(res));
}
// vue实现
this.$http.jsonp(
'http://www.domain2.com:8080/login',
{ params: {},
jsonp: 'onBack'
}
).then(res => { console.log(res) }
)
(2)domain:通过修改documen的domain属性,可以实现域和子域或者不同子域之间的传值,根据同源策略认为域和子域属于不同的域,比如www.baidu.com和sub.baidu.com是不同的域,我们无法在www.baidu.com中调用sub.baidu.com中定义的js方法,但是我们将document中domain属性改为baidu.com,浏览器就会默认他们在同一个域下,就能完成通信传值
仅限主域相同,子域不同的跨域应用场景,两个页面都通过js强制设置document.domain为基础主域,就实现了同域
<!-- 父窗口:http://www.domain.com/a.html -->
<iframe id="iframe" src="http://child.domain.com/b.html">
</iframe>
<script>
document.domain = 'domain.com';
var user = 'admin';
</script>
<!-- 子窗口:http://child.domain.com/b.html -->
<script>
document.domain = 'domain.com';
// 获取父窗口中变量
alert('get js data from parent ---> '+ window.parent.user);
</script>
(3)cors:跨域资源共享,支持get,post,head三种http请求方式,允许浏览器跨服务器发起XMLHttpRequest请求,从而解决Ajax只能永远同源使用的限制,整个通信过程由浏览器自动完成不需要用户参与,当浏览器发现AJAX请求资源,就会自动添加一些请求头信息,服务器根据需求配置CORS响应头信息,用户不会察觉,需要浏览器服务器同时支持,IE10以下不支持,关键是服务器,服务器实现cors接口,就能实现跨域通信;比如端口号不同,一个为3000,一个为5000,3000要访问5000端口号内部的js定义方法,可以在5000的服务器响应头添加Access-Controller-Allow-Origin属性:地址,指定同源策略地址,浏览器检测到响应头上带了CORS与本网站,就不会拦截请求响应
目前主流的跨域解决方案,服务端设置Access-Controller-Allow-Origin属性即可,若带cookie请求则
前后端需求设置
前端:检查设置是否带cookie: xhr.withCredentials = true,此方式发起请求会出现简单请求和复杂请求
简单请求:Content-Type的值为text/plain, multipart/form-data
,application/x-www-form-urlencoded
复杂请求:会在正式通信前增加一次HTTP查询请求(预检),通过option方法通过请求知道服务端是否允许跨域请求
Options预检请求:
请求头:(1)origin: 当前请求源,和响应头里的Access-Control-Allow-Origin 对标, 是否允许当前源访问,Origin是不可修改的
(2)Access-Control-Allow-Origin:本次真实请求的额外请求头,和响应头里的Access-Control-Allow-Headers对标,是否允许真实请求的请求头
(3)Access-Control-Request-Method:本次真实请求的额外方法,和响应头里的Access-Control-Allow-Methods对标,是否允许真实请求使用的请求方法
(4)window.name + iframe跨域
适合单向数据跨域请求,当window的location发送变化,重新加载页面时,name属性保持不变,可以在页面A中用iframe加载其他域的页面B,页面B通过js操作将需要传递的数据赋给window.name,iframe加载完成后,页面A修改iframe的地址将其编程同域就可以进行访问