跨域:当协议、子域名、主域名、端口号中任意一各不相同时,都算不同的“域”。不同的域之间相互请求资源,就叫“跨域”。浏览器的安全策略是需要同源,目的是保护用户的安全信息。如cookie、localStorage和IndexDB无法读取,无法操作跨域的iframe里的dom元素,ajax请求不能发送。
受到同源限制:
1.无法读取不同源的 Cookie、LocalStorage 和 IndexDB;
2.无法获得不同源的DOM ;
3.不能向不同源的服务器发送ajax请求。
不受同源限制:
在浏览器中,<script>
、<img>
、<iframe>
、<link>
等标签都可以跨域加载资源,而不受同源策略的限制
一、浏览器允许所有的请求
只需要在服务器端头部加上:header( "Access-Control-Allow-Origin: *" ); 一般为了安全起见,前端需设置token返回给后端,此方式在项目中并不适用
二、利用jsonp跨域
jsonp方式只适用GET请求,jsonp利用<script src=“”>标签跨域的特性,允许用户传递一个callback
或者开始就定义一个回调方法,参数给服务端,然后服务端返回数据时会将这个callback
参数作为函数名来包裹住json数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
//回调函数 function handleCallback (result) { var data = JSON.stringify(result); //json对象转成字符串 $("#val").val(data); } //向头部输入一个脚本,该脚本发起一个跨域请求 $("head").append("<script src='http://localhost:8000/index?callback=handleCallback'></script>");
三、利用cors实现跨域(Cross-Origin Resource Sharing---跨域资源共享)
CORS支持所有类型的HTTP请求,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制,整个CORS通信过程,都是浏览器自动完成,自动添加头部信息,不需要用户参与。
1、简单的请求: head,get,post请求和Content-Type为application/x-www-form-urlencoded
、multipart/form-data
、text/plain
2、非简单的请求:put,delete和Content-Type为application/json
非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest
请求,否则就报错。
3、cors方法也可以适用jsonp
function handleCallback(data) { $("#val").val(data); } $.ajax({ url: "http://localhost:8000/index", type: "GET", dataType: "jsonp", //指定服务器返回的数据类型 //jsonp: "theFunction", //指定参数名称 jsonpCallback: "handleCallback", //指定回调函数名称 success: function (data) { alert('success'); } });
四、代理跨域
如果是服务器跨域向多个不同的服务器发送请求就不会有跨域问题存在。因此,我们可以让浏览器只向一个服务器方式请求,让这个服务器代替浏览器去不同的服务器上请求资源再返回给浏览器。这个服务器就是代理服务器了。常用代理服务器nginx.
五、document.domain跨域
Cookie 是服务器写入浏览器的一小段信息,只有同源的网页才能共享。但是,两个网页一级域名相同,只是二级域名不同,浏览器允许通过设置document.domain共享 Cookie。另外,服务器也可以在设置Cookie的时候,指定Cookie的所属域名为一级域名。这样的话,二级域名和三级域名不用做任何设置,都可以读取这个Cookie。限制在解决一级域名相同二级域名不同的跨域问题,并且适用适用于 Cookie 和 iframe 窗口,LocalStorage 和 IndexDB 无法通过这种方法跨域.
eg: http://www.damonare.cn/a.html 和 http://damonare.cn/b.html 可通过把document.domain
设置成相同的值就可以在两个页面里操作Dom了。
六、window.name跨域
同一个浏览器标签页里打开了不同域名下的页面。这时候这两个页面你可以使用window.name
来传递参数。因为window.name
指的是浏览器窗口的名字,只要浏览器窗口相同,那么无论在哪个网页里访问值都是一样的。
缺点:监听子窗口window.name属性的变化,影响网页性能
七、postMessage跨域
HTML5y引入了一个全新的API,跨文档通信 API(Cross-document messaging)。这个API为window对象新增了一个window.postMessage
方法,允许跨窗口通信,不论这两个窗口是否同源。a就可以把它的LocalStorage,发送给b,b也可以把自己的LocalStorage发给a。
window.postMessage(message, targetOrigin, [transfer])
说明:
message是向目标窗口发送的数据;
targetOrigin属性来指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示无限制)或者一个URI(或者说是发送消息的目标域名);
transfer可选参数,是一串和message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。
另外消息的接收方必须有监听事件,否则发送消息时就会报错
window.addEventListener("message",onmessage);
onmessage接收到的message事件包含三个属性:
data:从其他 window 中传递过来的数据。
origin:调用 postMessage 时消息发送方窗口的 origin 。请注意,这个origin不能保证是该窗口的当前或未来origin,因为postMessage被调用后可能被导航到不同的位置。
source:对发送消息的窗口对象的引用; 您可以使用此来在具有不同origin的两个窗口之间建立双向通信。
// a页面 var popup = window.open('http://localhost:3000', 'title'); popup.postMessage('Hello World!', 'http://localhost:3000'); // b页面 window.onload=function () { window.addEventListener("message",onmessage); } function onmessage(event) { if(event.origin=="http://localhost:63343"){ // http://localhost:63343是发送方a的域名 console.log(event.data); // 'Hello World!' } console.log(event.data); // 'Hello World!' }
七、location.hash跨域
针对父窗口和iframe的子窗口之间通讯或者是window.open打开的子窗口之间的通讯。父窗口改变子窗口的url的#号后面的部分,后者把要传递的参数写在#后面,子窗口监听window.onhashchange事件,得到通知,读取window.location.hash解析出有用的数据。同样子窗口也可以向父窗口传递数据