摘要:跨域概述两个不同域互相请求,称为跨域,是由浏览器同源策略限制的一类请求场景。同源策略限制以下几种行为和无法读取无法获得请求不能发送目前主流的用于解决跨域问题的方法跨域缺点这种方法只适用于和窗口,和无法通过这种方法。
跨域概述
两个不同域互相请求,称为跨域,是由浏览器同源策略限制的一类请求场景。
--> 同源策略/SOP(Same origin policy)是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同。
同源策略限制以下几种行为:
1.) Cookie、LocalStorage 和 IndexDB 无法读取
2.) DOM无法获得
3.) AJAX 请求不能发送
目前主流的用于解决跨域问题的方法:
iframe跨域 document.domain+iframe缺点:这种方法只适用于 Cookie 和 iframe 窗口,LocalStorage 和 IndexDB 无法通过这种方法。
实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。
1.)父窗口:(http://www.domain.com/a.html)
2.)子窗口:(http://child.domain.com/b.html)
-->iframe是什么?iframe 元素会创建包含另外一个文档的内联框架(即行内框架)
postMessage跨域postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:
a.) 页面和其打开的新窗口的数据传递
b.) 多窗口之间消息传递
c.) 页面与嵌套的iframe消息传递
d.) 上面三个场景的跨域数据传递
用法:postMessage(data,origin)方法接受两个参数
data: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。
origin: 协议+主机+端口号,也可以设置为*,表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。
1.)a.html:(http://www.domain1.com/a.html)
2.)b.html:(http://www.domain2.com/b.html)
window.name+iframewindow.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。
1.)a.html:(http://www.domain1.com/a.html)
var proxy = function(url, callback) { var state = 0; var iframe = document.createElement("iframe"); // 加载跨域页面 iframe.src = url; // onload事件会触发2次,第1次加载跨域页,并留存数据于window.name iframe.onload = function() { if (state === 1) { // 第2次onload(同域proxy页)成功后,读取同域window.name中数据 callback(iframe.contentWindow.name); destoryFrame(); } else if (state === 0) { // 第1次onload(跨域页)成功后,切换到同域代理页面 iframe.contentWindow.location = "http://www.domain1.com/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("http://www.domain2.com/b.html", function(data){ alert(data); });
2.)proxy.html:(http://www.domain1.com/proxy....
中间代理页,与a.html同域,内容为空即可。
3.)b.html:(http://www.domain2.com/b.html)
总结:通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。
AJAX跨域 Vue ProxyTable本质是创建本地服务器,由本地服务器请求跨域服务器上的数据,服务器之间没有同源限制,
Access-Control-Allow-Origin参数设置在被请求的文件中添加一个header(IE10以下不支持)
jsonp方法缺点:只能实现get一种请求。
优点:简单适用,老式浏览器全部支持,服务器改造非常小。
原理:网页通过添加一个元素,向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。
原生实现//js function addScriptTag(src) { var script = document.createElement("script"); script.setAttribute("type","text/javascript"); script.src = src; document.body.appendChild(script); } window.onload = function () { addScriptTag("http://example.com/ip?callback=foo"); } function foo(data) { console.log("Your public IP address is: " + data.ip); }; //服务端JQuery方法
jquery会自动生成一个全局函数来替换callback=?中的问号,之后获取到数据后又会自动销毁,实际上就是起一个临时代理函数的作用。
get$.get("http://example.com/data.php?callback",function(){ alert("123"); },"jsonp");getJson
getJSON方法会自动判断是否跨域,不跨域的话,就调用普通的ajax方法;跨域的话,则会以异步加载js文件的形式来调用jsonp的回调函数。
$.getJson("http://example.com/data.php?callback=?",function(){ alert("123"); });ajax包裹jsonp
以上做法还有一种解释就是JQuery把jsonp的实现封装在了ajax中
$.ajax({ type: "GET", url: "http://www.b.com/jsonp.js" dataType: "jsonp", jsonp:"callback",//“callback”:任意名字都可以 success: function(data) { //对data的处理 }, error: function(jqXHR){ alert("发生错误:" + jqXHR.status); }, }); //服务端的修改 $jsonp = $_GET["callback"];//callback名字和请求的名字相同
-->ajax是什么?通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
vue实现jsonp//vue js this.$http.jsonp("http://www.domain2.com:8080/login", { params: {}, jsonp: "onBack" }).then((res) => { console.log(res); }) //node.js后端代码 var querystring = require("querystring"); var http = require("http"); var server = http.createServer(); server.on("request", function(req, res) { var params = qs.parse(req.url.split("?")[1]); var fn = params.callback; // jsonp返回设置 res.writeHead(200, { "Content-Type": "text/javascript" }); res.write(fn + "(" + JSON.stringify(params) + ")"); res.end(); }); server.listen("8080"); console.log("Server is running at port 8080...");WebSocket协议跨域
WebSocket是HTML5新的一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。
下面是一个例子,浏览器发出的WebSocket请求的头信息。
GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13 Origin: http://example.com
上面代码中,有一个字段是Origin,表示该请求的请求源(origin),即发自哪个域名。正是因为有了Origin这个字段,所以WebSocket才没有实行同源政策。因为服务器可以根据这个字段,判断是否许可本次通信。如果该域名在白名单内,服务器就会做出如下回应。
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chatCORS
CORS是跨源资源分享(Cross-Origin Resource Sharing)的缩写。它是W3C标准,是跨源AJAX请求的根本解决方法。相比JSONP只能发GET请求,CORS允许任何类型的请求。IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
简单请求只要同时满足以下两大条件,就属于简单请求。
(1) 请求方法是以下三种方法之一:
HEAD
GET
POST
(2)HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。
下面是一个例子,浏览器发现这次跨源AJAX请求是简单请求,就自动在头信息之中,添加一个Origin字段。
GET /cors HTTP/1.1 Origin: http://api.bob.com Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...
如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段。
Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Credentials: true Access-Control-Expose-Headers: FooBar Content-Type: text/html; charset=utf-8非简单请求
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。
非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。"预检"请求用的请求方法是OPTIONS,表示这个请求是用来询问的。"预检"请求的HTTP头信息:
Origin: 请求域名 Access-Control-Request-Method: 请求自身的方法 Access-Control-Request-Headers: 自定义的头部信息
发送请求后,服务器可以决定是否允许这种类型的请求,服务器通过在响应中发送如下头部与浏览器进行沟通
Access-Control-Allow-Origin: 相同的源信息,可以是* Access-Control-Allow-Methods: 允许的方法 Access-Control-Allow-Headers: 允许的头部 Access-Control-Max-Age:应该讲这个preflight缓存多久
preflight请求结束后,结果就按照响应中指定的时间缓存起来,而为此付出的代价只是第一次发送请求的时候会多发送一次HTTP请求。
带凭据的请求CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段。
Access-Control-Allow-Credentials: true
另一方面,开发者必须在AJAX请求中打开withCredentials属性。
var xhr = new XMLHttpRequest(); xhr.withCredentials = true;
前端XMLHttpRequest请求代码
var xhr = new XMLHttpRequest(); // IE8/9需用window.XDR兼容 xhr.withCredentials = true;// 前端设置是否带cookie xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { alert(xhr.responseText); } }; xhr.open("post", "http://www.domain2.com:8080/login", true); xhr.setRequestHeader("Content-Type", "application/json"); xhr.send();
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/93461.html
摘要:同源策略所谓同源是指协议,域名,端口均相同。同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。需注意的是由于同源策略的限制,所读取的为跨域请求接口所在域的,而非当前页。 一、什么是跨域 1.URL解析 URL (Uniform Resource Locator )统一资源定位符(URL)是用于完整地描述Internet上网页和其他资源的地址的...
摘要:关于咱们先了解在开发过程中的主要作用解决跨域负载均衡一解决跨域如果要理解什么是跨域广义上的跨域是指一个域下的文档或脚本试图去请求另一个域下的资源。标记为备份服务器。当主服务器不可用时,将传递与备份服务器的连接。 关于nginx,咱们先了解nginx在开发过程中的主要作用 nginx解决跨域 nginx负载均衡 一、nginx解决跨域 如果要理解什么是跨域 广义上的跨域是指一个域下的...
摘要:实现跨域的原理通过方式请求载入并执行一个文件,相当于通过的形式的导入一个外部的方法语法该函数是简写的函数,等价于在中,您可以通过使用形式的回调函数来加载其他网域的数据,如。将自动替换为正确的函数名,以执行回调函数。 更多详情见http://blog.zhangbing.club/Ja... 最近在项目开发的过程中遇到一些Javascript 跨域请求的问题,今天抽空对其进行总结一下,以...
摘要:类似这样而在客户端我们只需要定义一个预定好的回调函数即可。处理跨域请求得到的数据其中的是我们在客户端定义好的在数据请求成功后要执行的回调函数。 跨域产生的原因 跨域是由浏览器的同源策略引起的,即不同源(协议,域名,端口中其中有一个不同)的js是不能读取对方的资源的。当要网站中的js要请求其他网站的数据时就会产生跨域问题,就像下面这样,浏览器会报错。 showImg(https://se...
阅读 2898·2021-10-27 14:19
阅读 536·2021-10-18 13:29
阅读 1127·2021-07-29 13:56
阅读 3545·2019-08-30 13:19
阅读 1926·2019-08-29 12:50
阅读 1034·2019-08-23 18:16
阅读 3520·2019-08-22 15:37
阅读 1897·2019-08-22 15:37