1.名词解释
域:空间,范围,同源
同源策略
一种浏览器的安全策略,是浏览器的最基本的安全功能。
一段脚本只能读取来自于同一来源的窗口和文档的属性,这里的同一来源指的是主机名(域名)、协议(http/https)和端口号的组合。在没明确授权的情况下,不能读写对方的资源,它是浏览器最核心也最基本的安全功能。
所谓同源是指,域名,协议,端口相同。
域名
服务器ip地址的别名,IP地址绑定后访问这个域名就相当于访问了这个IP地址
协议
网络设备之间的通信协议,双方实体完成通信或服务所必须遵循的规则和约定。
http/https(网络浏览协议)
ftp(文件共享协议)
file(本地协议)
可以通过winwow.location.hostName
可以通过修改host地址访问测试环境
端口
一种网络传输口
80:www
21:ftp
只要不同源就会出现跨域情况
2.解决跨域问题
2.1 后端提高权限
标准浏览器的XMLHttpRequest() + 后端文件设置请求头权限(HTML5)新API
低版本浏览器的XMLHttpRequest()不支持与后端配合
2.2 后端代理
后端先把数据请求到当前服务器,然后前端使用ajax去请求后端数据
弊端:会对开发项目造成不稳定影响(请求地址页面发生了改变,自己的页面也会发生改变)
2.3 flash跨域
flash快要死了,不管它
2.4 ifream
2.5 jsonp
json+padding ,填充式的json。
jsonp的实质,是后端调用了一个函数,然后传入了实参,在本页面就需要一个同名的函数去接收数据。这个函数必须放在全局
- 1.创建一个
script标签 - 2.给src设置请求地址
- 3.将script标签放在head中
<script>
function fn3(){
console.log(arr);
document.getElementsByTagName("head")[0].removeChild(document.getElementsByTagName("head")[0].lastElementChild);
};
window.onload = function(){
var script = document.createElement("script");
script.scr = "跨域访问的地址";
document.getElementsByTagName("head")[0].appendChild(script);
};
</script>
后端设置一个回调函数就可以让前端修改函数名。
前端声明函数,后端传入实参,前端执行函数。
jsonp的缺点:
ajax的数据jsonp无法使用,但是jsonp的数据ajax是可以用的。
jsonp只能通过get请求,不能使用post。
ajax的缺点:
无法返回上一次操作
3. 封装JSONP
function jsonp(json){
var sd;
var settings = {
url:json.url || '',
data:json.data || {},
succ:json.succ || '',
cbName:json.cbName || 'callback',
callback:json.callback || 'jQuery'+new Date().getTime(),
fail:json.fail || ''
};
var timer = null;
var head = document.getElementsByTagName('head')[0];
//创建的script标签的src = 传进来的url + fn3...
var oS = document.createElement('script');
oS.className = 'error';
settings.data[settings.cbName] = settings.callback;
var arr = [];
for(var attr in settings.data){
arr.push(attr+'='+settings.data[attr]);
}
settings.data = arr.join('&');
oS.src = settings.url + '?' + settings.data;
head.appendChild(oS);
//因为接受的函数必须挂在window下(全局),所以才用window[callback],callback又是可变的,所有用[]
window[settings.callback] = function(json){
//为了清除失败的那个定时器
clearTimeout(timer);
//遗留下来的script标签
error = head.getElementsByClassName('error');
//找到所有class名为error的script标签,并且清除掉
for(var i=0,len=error.length;i<len;i++){
head.removeChild(error[0]);
}
//如果传了并且是个函数就执行需求代码,将数据传到外面使用
if(settings.succ && typeof settings.succ === 'function'){
settings.succ(json);
}
if(error.length){
head.removeChild(error);
}
}
//一段时间之后,如果指定的script标签还在
//说明没有返回数据,一般是网络断开调用失败的函数
//当然也可以在断开的时候将本次的script标签清掉。
clearTimeout(timer);
timer = setTimeout(function(){
sd = head.getElementsByClassName('saodong');
if(sd.length){
if(settings.fail && typeof settings.fail === 'function'){
settings.fail();
// head.removeChild(oS);
}
// console.log(sd);
// alert('请检查网络!!');
}
},3000);
}