300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > 跨域问题详解——九种解决跨域方法

跨域问题详解——九种解决跨域方法

时间:2020-02-15 17:39:32

相关推荐

跨域问题详解——九种解决跨域方法

跨域是前端再常见不过的问题了,下面主要针对跨域做一次总结,一次理清楚。

一、jsonp解决跨域

jsonp解决跨域问题的原理是:script不受同源策略的影响。

//前端代码:<!DOCTYPE html><html lang="cn"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head><body><script>function callback(res) {console.log(res)}</script><script src="http://127.0.0.1:3000?fn=callback"></script></body></html>

//服务器代码var http = require('http');var server = http.createServer();var qs = require("querystring")server.on("request", (req, res) => {let params = qs.parse(req.url.split("?")[1])let obj = {name:"张三", age :20}res.end(params.fn + "(" + JSON.stringify(obj) +")")})server.listen(3000, () => {console.log("服务器已打开")})

jsonp实现跨域:前端通过script标签将函数以参数的形式传递给后台,后台通过解析请求的字符串,拿到该函数,然后让该函数以执行的状态返回给前端,并且在其中传入数据。不过jsonp请求只能支持get请求方式。

二、document.domain + iframe实现跨域

此方案只适用于主域相同,子域不同的页面实现跨域。

父窗口的地址为 /a.html<body><iframe src="/b.html"></iframe><script>document.domain = "" var name = "哈哈哈"</script></body>

子窗口的地址是 /b.html<body><script>document.domain = ""console.log(window.parent.name) //哈哈哈</script></body>

总结:document.domain + iframe实现跨域原理是,当子域名不一致的情况下,需要在父级和子级都需要使用document.domain强制设置基础主域名。然后在父级中使用iframe将子集引入,这样在子集就能拿到父级的数据了。

三、location.hash + iframe实现跨域

存在两个页面(a, b),如果a,b页面同域,则可以直接进行数据通信。如果a, b不同域时,可以通过location.hash + iframe来实现跨域数据传输。

a页面所在的域为:/a.htmla页面的代码为:<body><iframe src="/b.html"></iframe><script>let iframe = document.querySelect("iframe")setTimeout(() => {iframe.src = iframe.src + "#user=admin"})</script></body>

<body><script>window.onhashchange = function(){console.log(location.hash) //#user=admin}</script></body>

总结:上面两个页面处于不同的域中,在a页面中使用iframe引入了b页面,通过改变b页面的hash值,来实现将数据传递给b页面的目的。同样b页面使用onhashchange监听函数,监听hash值的改变。本例中hash值为user=admin,这样就能拿到这个字符串,然后最终在b页面中解析,最终实现数据跨域传输。

四、window.name + iframe实现跨域

window.name存在这样一个特点就是在不同的页面下,或者是在不同的域下面其值都是存在的,并且name的长度非常长(2MB)

a页面的地址是:/a.html<body><script>var proxy = function (url, callback) {var state = 0;var iframe = document.createElement('iframe');// 加载跨域页面iframe.src = url;// onload事件会触发2次,第1次加载跨域页,并留存数据于window.nameiframe.onload = function () {if (state === 1) {// 第2次onload(同域proxy页)成功后,读取同域window.name中数据callback(iframe.contentWindow.name);destoryFrame();} else if (state === 0) {// 第1次onload(跨域页)成功后,切换到同域代理页面iframe.contentWindow.location = '/proxy.html';state = 1;}};document.body.appendChild(iframe);// 获取数据以后销毁这个iframe,释放内存;这也保证了安全(不被其他域frame js访问)function destoryFrame() {iframe.contentWindow.document.write('');iframe.contentWindow.close();document.body.removeChild(iframe);}};// 请求跨域b页面数据proxy('/b.html', function (data) {console.log(data)});</script></body>

b页面的地址为:/b.html中间代理页,与a.html同域,内容为空即可。

c页面的地址是:/c.html<script>window.name = "张三"</script>

总结:window.name + iframe实现的思路:本例中需要在a页面的中访问到c页面的数据,但是由于跨域,无法进行访问。此时设置一个代理b页面,起到桥梁的作用。首先在a页面中设置iframe并且首先将其的src值设置为页面c的地址。由于iframe需要执行两次onload,此时我们可以在iframe第一次加载之后,改变其src为页面b的地址。这样iframe上的window.name了,当改变src时,window.name也不会改变。这样a和b就是同源的了,访问数据就不受限制了。最后需要销毁iframe。

五、postMessage实现跨域

postMessage是html5中新增的api,是window属性中位数不多的可以实现跨域的。其存在两个参数,一个是发送的数据(使用JSON.stringify()来格式化一下)第二个参数是:origin,表示为主机 + 协议 + 端口,"*"表示向全部的端口发送,"/"表示向当前窗口同源的窗口发送。

a页面的地址为:/a.html<body><iframe src="/b.html"><script>let iframe = document.querySelector("iframe")iframe.onload = function(){let obj = {name:"张三",age:20 }iframe.contentWindow.postMessage(JSON.stringify(obj),"")//向domain2发送数据}//监听domain2发送来的数据window.addEventListener("message", function(data) {console.log(data) //"data"})</script></body>

b页面的地址是:/b.html<script>window.addEventListener("message", function(data){console.log(data) //{name:"张三",age:20}window.parent.postMessage("data", "")})</script>

六、跨域资源共享(CORS)

目前跨域使用CORS比较多,如果不需要携带cookie,则只需要在服务端设置Access-control-Allow-Origin即可,如果需要携带cookie,则见下文。

前端设置1、原生的ajax// 前端设置是否带cookiexhr.withCredentials = true;2、实例代码var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容// 前端设置是否带cookiexhr.withCredentials = true;xhr.open('post', ':8080/login', true);xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');xhr.send('user=admin');xhr.onreadystatechange = function() {if (xhr.readyState == 4 && xhr.status == 200) {alert(xhr.responseText);}};

node后台进行设置var http = require('http');var server = http.createServer();var qs = require('querystring');server.on('request', function(req, res) {var postData = '';// 数据块接收中req.addListener('data', function(chunk) {postData += chunk;});// 数据接收完毕req.addListener('end', function() {postData = qs.parse(postData);// 跨域后台设置res.writeHead(200, {'Access-Control-Allow-Credentials': 'true',// 后端允许发送Cookie'Access-Control-Allow-Origin': '', // 允许访问的域(协议+域名+端口)/* * 此处设置的cookie还是domain2的而非domain1,因为后端也不能跨域写cookie(nginx反向代理可以实现),* 但只要domain2中写入一次cookie认证,后面的跨域接口都能从domain2中获取cookie,从而实现所有的接口都能跨域访问*/'Set-Cookie': 'l=a123456;Path=/;Domain=;HttpOnly' // HttpOnly的作用是让js无法读取cookie});res.write(JSON.stringify(postData));res.end();});});server.listen('8080');console.log('Server is running at port 8080...');

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。