同源策略
同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。
同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。
什么情况下会造成跨域?
同源组策略:Ajax请求地址与当前页面的地址必须得是同协议,同主机,同端口才可以正常发送Ajax请求,这三者有任何一个不一样,则判定此次请求是跨域请求,浏览器会阻止这个请求行为。(不同源之间的交换资源,会造成跨域)
以下任意一种都是不同源
http:// | 协议不同 |
www | 子域名不同 |
baidu.com | 主域名不同 |
8080 | 端口号不同 |
www.baidu.com | ip地址和网址不同 |
JSON:前后端交换数据的一种格式。
* JSON字符串:往往都是在后端向前端发送数据时传输的格式。
* JSON对象:往往都是前端希望得到的。数据或对象或它们之间的嵌套。
JSON字符串与JSON对象之间的转换
* JSON.parse(JSON格式的字符串):正解析,将JSON字符串转换为JSON对象,没有副作用。
* JSON.stringify(JSON对象):反解析,将JSON对象转换为JSON字符串,没有副作用。
跨域的解决方式
* CORS(跨源域资源共享机制)
* 服务器反向代理
* JSONP
1.CORS
主要是服务端进行配置首部字段
Access-Control-Allow-Origin: http://aa.com
Access-Control-Allow-Methods: <method>[, <method>]*
2.JSONP
JSONP:一种解决跨域问题的方法。工作机制:利用动态创建一个script标签并利用它的src属性向服务器发送一次HTTP请求,并提前声明好一个回调函数,回调函数的函数名利用callback请求参数传递给后端。后端接收到来自前端的请求后,获取callback请求的请求参数并拼接一个调用函数的JS代码段并将要返回给前端的数据以实参的形式存在。前端接收到来自后端的响应后,会将后端的返回内容当做JS代码来执行即调用一个函数,并用一个形参来接收后端向要传递过来的数据。
1.Web页面上用<script> 引入js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥
有"src"这个属性的标签都拥有跨域的能力,比如<script>、<img>、<iframe>)2.于是我们把数据放到服务器上,并且数据最好为json形式(因为js可以轻松处理json数据)
3.事先定义好用于处理跨域获取数据的函数,如 function doJSON(data){}。
4.因为我们无法监控通过<script>的src属性是否把数据获取完成,所以可以在创建script标签
且给src赋值时需要将用于处理获取数据的函数的函数名以参数形式传到服务端,比如可在src上
添加参数cb='doJSON',服务端会将参数cb的值与要返回的数据拼接成函数执行的形式,比如:
doJSON(数据)例如:
<script>
var script = document.createElement('script');
script.src = 'http://aaa.cc.com?cb=doJSON'; // doJSON 是页面存在的回调方法,参数就是想得到的json
document.body.appendChild(script);
// 用于处理跨域获取数据的函数
function doJSON(data){
console.log(data);
}
</script>
利用jQuery 获取jsonp
利用jQuery可以直接得到想要的json数据,同样是上面的jsonp:
$("#getJsonpByJquery").click(function () { $.ajax({ url: 'http://localhost:2701/home/somejsonp', dataType: "jsonp", jsonp: "callback", success: function (data) { console.log(data) } }) })
3. document.domain(针对基础域名相同的情况)
基础域名相同:jd.bb.com 和 sz.bb.com
4. iframe
iframe就是一个标签,可以在一个网页中嵌套另一个页面。一般主要用来广告植入、在线编辑等。但是iframe也有它的缺点,比如会阻塞页面加载。window 的 onload 事件需要在所有 iframe 加载完毕后(包含里面的元素)才会触发。通过 JavaScript 动态设置 iframe 的 src 可以避免这种阻塞情况。
1.获取iframe内的window
var iframeWindow = document.getElementsByTagName('iframe')[0].contentWindow;
var iframe = window.frames['index2'];//window.frames['iframe的name'];
//IE6 IE7的写法
var ieIframe1 = document.frames['index2'].contentWindow;
var ieIframe2 = document.frames[0].contentWindow;
2.子窗口获取父级窗口 window.parent 顶级窗口 window.top3.判断iframe是否加载完成
非ie下使用onload事件
iframe(dom元素).onload = function () {}
ie下使用onreadystatechange或者设定计时器
iframe.onreadystatechange = function(){
if (iframe.readyState == 'complete' || iframe.readyState == 'loaded'){
console.log("Local iframe is now loaded.");
}
}
5. 脚本试图访问的框架内容必须遵守同源策略,并且无法访问非同源的window对象的几乎所有属性。同源策略同样适用于子窗体访问父窗体的window对象。解决方式有document.domain、location.hash(解决子页面访问父页面数据的问题)、window.name(解决父页面访问子页面数据的问题)以及html5中的postMessage。
5.1 window.name:解决父页面访问子页面的数据问题
特点是在当前窗口不关闭的情况下,无论是页面重载刷新还是换了一个页面,name值都不变。
//主页面
var ifr = document.getElementsByTagName('iframe')[0];
var flag = true;
ifr.onload = function () {
if (flag) {
//proxy.html代理文件,一般是一个没有任何内容的html文件需要和主页面在同一域下
ifr.src = './proxy.html';
flag = false;
} else {
console.log(ifr.contentWindow.name)
}
}
//子页面
window.name = 'data';
5.2 location.hash:解决子页面访问父页面数据的问题
主要是利用锚点的特性,改变hash值不会刷新页面。可以在父页面将数据以hash值的方式传递,但是子页面需要监控hash值的变化。
缺点:1、传递数据量有限 2、不太安全
//主页面
var ifr = document.getElementsByTagName('iframe')[0];
var num = 12;
var src = ifr.src;
document.onclick = function(){
num++;
ifr.src = src + '#' + num;
}
//子页面
window.onhashchange = function () {
console.log(location.hash.slice(1))
}
///如果不支持hashchange事件,需要利用定时器监控
var lastHash = location.hash;
setInterval(function () {
if (lastHash != location.hash) {
console.log(location.hash.slice(1));
lastHash = location.hash;
}
}, 100)
5.3 postMessage
语法:otherWindow.postMessage(message, targetOrigin, [transfer])
otherWindow:对接收信息页面的window的引用,比如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。
message:想要传递的数据
targetOrigin:指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示无限制)或者一个URI
/*
* A窗口的域名是<http://example.com:8080>,以下是A窗口的script标签下的代码:
*/
var ifr = document.getElementById('ifr');
var targetOrigin = 'http://example.org';
ifr.contentWindow.postMessage('I was there!', targetOrigin);function receiveMessage(event)
{
// 我们能相信信息的发送者吗? (也许这个发送者和我们最初打开的不是同一个页面).
if (event.origin !== "http://example.org")
return;
// event.source 是我们通过window.open打开的弹出页面 popup
// event.data 是 popup发送给当前页面的消息
}
window.addEventListener("message", receiveMessage, false);/*
* B窗口的域名是<http://example.org>
*/
window.addEventListener('message', function(event){
// 通过origin属性判断消息来源地址
if (event.origin == 'http://example.com:8080') {
event.source.postMessage("YEAH" , event.origin);
}
}, false);
6.Flash
https://www.cnblogs.com/loveis715/p/4592246.html
http://www.cnblogs.com/AS30/archive/2012/09/21/2696788.html