当前位置: 首页 > Web前端 > HTML5

前端跨域处理

时间:2023-04-04 23:42:08 HTML5

由于浏览器的同源策略保护机制,浏览器无法执行其他来源的脚本。不同域之间通过js进行数据传输或通信,比如使用ajax向不同域请求数据,或者在页面中使用js获取不同域的frame(iframe)中的数据,称为跨域。所谓同源,就是协议、域名(IP)、端口都相同。只要其中一个不同,就是跨域的,不能交换数据。例如:注意localhost和本机的IP地址也是跨域的。当浏览器执行一个javascript脚本时,它会检查脚本属于哪个页面。如果不是同源页面,则不会执行。解决跨域的方法有几种:方法一:设置webpack服务器代理1.工程化的前端项目,在本机开发时,后台界面可能会出现跨域,可以设置webpack服务器代理服务器的地址将本地机器的请求转发到与接口同源的地址。首先安装插件:webpack-dev-server,然后在config文件夹中找到index.js文件,在dev对象下的proxyTable字段中添加对应需要替换的地址。module.exports={...devServer:{//本地开发服务器设置...port:8080,//当前端口号proxyTable:{//服务器代理设置'/v3/admin':{//需要代理的interfaceformtarget:'http://localhost:8700',//代理当前端口号为8700changeOrigin:true,secure:false}}}}以上设置都是包含'/v3/admin'字段的接口,从原来的localhost:8080代理到localhost:8700,改成'http://localhost:8700/v3/admin'就可以得到8700端口的内容方法二:使用CORS进行数据传输CORS是W3C标准,并且它的全称是“跨源资源共享”。它允许浏览器向跨域服务器发送XMLHttpRequest请求,从而克服AJAX只能在同源上使用的限制。CORS标准增加了一组新的HTTP头字段,允许服务器声明哪些源站有权访问哪些资源。另外,规范要求对于那些可能对服务器数据产生副作用的HTTP请求方式(尤其是GET以外的HTTP请求,或者某些MIME类型的POST请求),浏览器必须先使用OPTIONS方式发起preflight请求(preflightrequest),从而知道服务器是否允许跨域请求。服务器确认权限后,才发起实际的HTTP请求。在preflight请求的返回中,服务端还可以通知客户端是否携带身份凭证(包括Cookies和HTTP认证相关数据)。CORS需要浏览器和服务器都支持,浏览器需要ie8以上。浏览器端的写法:functionCORSRequest(method,url,opation,callback){varxhr=newXMLHttpRequest();if("withCredentials"inxhr){//此时支持CORS//检查XMLHttpRequest对象是否有"withCredentials"属性//"withCredentials"只存在于XMLHTTPRequestlevel2对象中}else{//否则检查是否支持XDomainRequest//XDomainRequest只存在于IE中,是IE8和IE9用来支持CORS请求的方法xhr=newXDomainRequest();}xhr.open(方法,网址,真);if(method=="POST"){//可以设置不同请求方式的运行,所有请求都可以单独设置xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");//设置请求头xhr.send(opation);//向服务器发送数据}else{xhr.send();}xhr.onload=function(){回调(xhr.responseText);}};functionnotice(data){console.log(data)}CORSRequest('POST','http://example.com','Datapassedtotheserver',no票);服务器端写法:Apache:Apache需要使用mod_headers模块来激活HTTP头的设置,默认是激活的。你只需要在Apache的配置文件中添加如下内容,或者配置:HeadersetAccess-Control-Allow-Origin*PHP:前端只需要将XMLHttpRequest的请求地址设置为'a.php'即可。方法五:使用window.namewindow对象有一个name属性,它有一个特点:即在一个窗口(window)的生命周期内,该window加载的所有页面共享一个window.name,每个页面都有对window.name有读写权限,window.name在一个窗口加载的所有页面中是持久化的,不会在加载新页面时被重置。例如:有一个页面a.html,里面有这样的代码:看b.html页面的代码:a.html页面加载后3秒,跳转到b.html页面,结果是:我们看到在b.html页面上,成功获取了其上一页a.html为window.name设置的值。如果之后所有加载的页面都没有修改window.name,那么所有这些页面获取到的window.name的值就是a.html页面设置的值。当然,这些页面中的任何一个都可以根据需要修改window.name的值。注意window.name的值只能是字符串形式。这个字符串的最大大小可以允许2M左右甚至更大的容量,这取决于不同的浏览器,但一般来说足够了。在上面的例子中,我们使用的页面a.html和b.html是同一个域的,但是即使a.html和b.html是不同域的,上面的结论也是适用的,这正是的原理使用window.name进行跨域。此方法需要与iframe配合使用。比如有一个www.example.com/a.html页面,需要使用a.html页面中的js获取位于不同位置的另一个页面www.cnblogs.com/data.html中的数据领域。data.html页面中的代码非常简单。就是给当前的window.name设置一个a.html页面要获取的数据值。data.html中的代码:那么在a.html页面中,我们如何加载data.html页面呢?显然我们不能通过改变a.html页面中的window.location直接加载data.html页面,因为即使a.html页面不跳转我们也想获取data.html中的数据。答案是在a.html页面中使用一个隐藏的iframe来充当中间人。iframe获取data.html的数据,然后a.html获取iframe获取的数据。如果作为中间人的iframe要获取data.html中window.name设置的数据,只需要将iframe的src设置为www.cnblogs.com/data.html即可。那么a.html要获取iframe获取的数据,即如果要获取iframe的window.name的值,还必须将iframe的src设置为与a.html同域页。否则按照前面说到的同源策略,a.html是无法访问到iframe中的window.name属性的。这就是整个跨域过程。看a.html页面的代码:上面的代码只是最简单的原理演示代码。可以用js封装上面的过程,比如动态创建iframe,动态注册各种事件等,当然为了安全起见,get完数据后,作为代理的iframe也可以销毁。方法六:使用window.postMessagewindow.postMessage(message,targetOrigin)方法是html5新引入的特性,可以用来向其他window对象发送消息,不管window对象属于同源还是异源起源。目前IE8+、FireFox、Chrome、Opera等浏览器已经支持window.postMessage方法。调用postMessage方法的window对象就是指接收消息的window对象。该方法第一个参数message为要发送的消息,类型只能是字符串;第二个参数targetOrigin用于限定接收消息的窗口对象所在域。如果不想限制域,可以使用通配符*。需要接收消息的窗口对象可以通过监听自身的消息事件获取传入的消息,消息内容保存在事件对象的data属性中。上面说的给其他window对象发送消息,其实是指一个页面有几个frame的情况,因为每个frame都有一个window对象。让我们看一个简单的例子。有两个页面,运行a页面后得到的结果:我们看到b页面已经成功收到消息了。使用postMessage跨域传输数据比较直观方便,缺点是IE6、IE7不支持,要不要用还是要根据实际需要决定。