(转自jlin991的博客)
什么是跨域
老生常谈的问题了。下面列出一个表格:
URL | 说明 | 是否跨域 |
---|---|---|
http://www.a.com/a.js http://www.a.com/b.js | 同一个域名 | 否 |
http://www.a.com/lab/a.js http://www.a.com/script/b.js | 同一个域名,不同文件夹 | 否 |
http://www.a.com:8080/a.js http://www.a.com/b.js | 同一个域名,不同端口 | 是 |
http://www.a.com/a.js http://79.23.1.21/b.js | 域名与域名对应IP | 是 |
http://www.a.com/a.js http://script.a.com/b.js | 主域和子域 | 是 |
http://www.a.com/a.js http://a.com/b.js | 一级域名和二级域名 | 是 |
http://www.XXX.com/a.js http://www.a.com/b.js | 不同域名 | 是 |
http://localhost/a.js http://127.0.0.1/b.js | 本地和本地对应的IP | 是 |
而且跨域问题上,域仅仅是通过URL的首部来识别的,而不会去尝试判断两个域是否在同一个IP上(这涉及到DNS解析)
下面介绍几种能实现跨域的方法 图像Ping
JS高程提到的一个方法,利用的是img的src可以跨域。
var img= new Image();
img.onload=img.onerror=function(){
console.log('Done~!');
};
img.src='http://www.example.com/test?name=Nicolas';
- 1
- 2
- 3
- 4
- 5
- 6
- 7
仅仅是 浏览器 –> 服务器
1.只能发送get请求,并且无法获得任何服务器的响应。
2. 仅仅是单向的数据传递,浏览器-->服务器
- 1
- 2
JSON with Padding
JSONP 两部分组成: 回调函数+数据
JSONP中的回调函数
响应到来的时候,应该在页面中调用的函数。
JSON就是数据
数据是传入回调函数中的JSON数据。
JSONP的原理
动态添加一个
- 1
- 2
- 3
可以说jsonp的方式原理上和是一致的(qq空间就是大量采用这种方式来实现跨域数据交换的)。JSONP是一种脚本注入(Script Injection)行为,所以有一定的安全隐患。
服务端代码可能是这样的
1,'b'=>2,'c'=>3,'d'=>4,'e'=>5);
$result=json_encode($arr);
//echo $_GET['callback'].'("Hello,World!")';
//echo $_GET['callback']."($result)";
//动态执行回调函数
$callback=$_GET['callback'];
//得到回调函数
echo $callback."($result)";
//输出,result作为参数传递
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
我们其实是要querystring,获取url中传递的参数,这里是callback,然后把callback的值’jsonpCallback’包裹要传递的json字符串。也就像这样:
jsonpCallback({“name”:”xxx”,”id”:23});
返回的就是用这个callback的值包裹的json数据。
然后这个回调函数就会被执行。因为你创建了script标签然后函数在里面被调用执行了。
jQuery的实现
原理是一样的,只不过我们不需要手动的插入script标签以及定义回掉函数。
jquery会自动生成一个全局函数来替换callback=?中的问号,之后获取到数据后又会自动销毁,实际上就是起一个临时代理函数的作用。
$.getJSON方法会自动判断是否跨域,不跨域的话,就调用普通的ajax方法;跨域的话,则会以异步加载js文件的形式来调用jsonp的回调函数。
jQuery源码部分:
//Build temporary JSONP function
if( s.dataType === "json" && (s.data && jsre.test(s.data) || jsre.test(s.url)) ) {
jsonp = s.jsonpCallback || ("jsonp" + jsc++);
// Replace the =? sequence both in the query string and the data
if ( s.data ) {
s.data = https://www.it610.com/article/(s.data +"").replace(jsre, "=" + jsonp + "$1");
}
/*...*/
if ( s.cache === false && type === "GET" ) {
var ts = now();
// try replacing _= if it is there
var ret = s.url.replace(rts, "$1_=" + ts + "$2");
// if nothing was replaced, add timestamp to the end
s.url = ret + ((ret === s.url) ? (rquery.test(s.url) ? "&" : "?") + "_=" + ts : "");
}// If data is available, append data to url for get requests
if ( s.data && type === "GET" ) {
s.url += (rquery.test(s.url) ? "&" : "?") + s.data;
}// Watch for a new set of requests
if ( s.global && ! jQuery.active++ ) {
jQuery.event.trigger( "ajaxStart" );
}// Matches an absolute URL, and saves the domain
var parts = rurl.exec( s.url ),
remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host);
// If we're requesting a remote document
// and trying to load JSON or Script with a GET
if ( s.dataType === "script" && type === "GET" && remote ) {
var head = document.getElementsByTagName("head")[0] || document.documentElement;
var script = document.createElement("script");
script.src = https://www.it610.com/article/s.url;
// Handle Script loading
if ( !jsonp ) {
var done = false;
// Attach handlers for all browsers
script.onload = script.onreadystatechange = function() {
if ( !done && (!this.readyState ||
this.readyState ==="loaded" || this.readyState === "complete") ) {
done = true;
success();
complete();
// Handle memory leak in IE
script.onload = script.onreadystatechange = null;
if ( head && script.parentNode ) {
head.removeChild( script );
}
}
};
}// Use insertBefore instead of appendChild to circumvent an IE6 bug.
// This arises when a base node is used (#2709 and #4378).
head.insertBefore( script, head.firstChild );
// We handle everything using the script element injection
return undefined;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
然后创建了script标签,构造这个script片段,并且追加到了原文档的head标签后面。
还有就是判断浏览器的脚本onreadystatechange事件,判断readyState是loaded或complete两个都要判断。
NOTE
因为无论是哪个属性都表示资源已经可用了。有时候readyState会停在“loaded”有时候会跳过”loaded”直接完成)
JSONP的优点
- JSON可读性好,在JS中容易处理
- 比XML轻了很多
- PHP对JSON的支持也不错
【javascript|跨域解决方案JSONP】JSONP很好用,但是它有如下的缺点:
- JSONP是从其他域中加载代码执行的,如果其他域不安全(服务器端不安全),很有可能在响应中夹带一些恶意代码,此时除了完全放弃JSONP调用外没有办法。
- 其次,确定JSONP是否请求成功不容易。因为如果动态脚本插入有效那么就执行调用,如果无效就静默失败,失败没有任何提示~
- 用eval()解析也是容易出现安全问题
推荐阅读
- 操作系统|[译]从内部了解现代浏览器(1)
- web网页模板|如此优秀的JS轮播图,写完老师都沉默了
- JavaScript|vue 基于axios封装request接口请求——request.js文件
- vue.js|vue中使用axios封装成request使用
- JavaScript|JavaScript: BOM对象 和 DOM 对象的增删改查
- JavaScript|JavaScript — 初识数组、数组字面量和方法、forEach、数组的遍历
- JavaScript|JavaScript — call()和apply()、Date对象、Math、包装类、字符串的方法
- JavaScript|JavaScript之DOM增删改查(重点)
- javascript|vue使用js-xlsx导出excel,可修改格子样式,例如背景颜色、字体大小、列宽等
- javascript|javascript中的数据类型转换