在项目中遇到一个jsonp跨域的问题,于是仔细的研究了一番jsonp跨域的原理。搞明白了一些以前不是很懂的地方,比如:
1)jsonp跨域只能是get请求,而不能是post请求;
2)jsonp跨域的原理到底是什么;
3)除了jsonp跨域之外还有那些方法绕过“同源策略”,实现跨域访问;
4)jsonp和ajax,或者说jsonp和XMLHttpRequest是什么关系;
等等。
1.同源策略
说到跨域,首先要明白“同源策略”。同源是指:js脚本只能访问或者请求相同协议,相同domain(网址/ip),相同端口的页面。
我们知道,js脚本可以访问所在页面的所有元素。通过ajax技术,js也可以访问同一协议,同一个domain(ip),同一端口的服务器上的其他页面,请求到浏览器端之后,利用js就可以进行任意的访问。但是对于协议不同, 或者domain不同或者端口不同的服务器上的页面就无能为力了,完全不能进行请求。
下面在本地搭建两个tomcat,分别将端口设为8080,和8888,进行相关实验。显然他们的端口是不同的。演示如下:
http://localhost:8888/html4/ajax.html的代码如下:
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
|
<!
doctype
html>
<
html
>
head
>
name="keywords" content="jsonp">
name="description" content="jsonp">
title
>jsonp</
>
style
type="text/css">
*{margin:0;padding:0;}
a{display:inline-block;margin:50px 50px;}
</
>
>
body
>
a
href="javascript:;" onclick="myAjax();">click me</
>
script
type="text/javascript" src="js/jquery-1.11.1.min.js"></
>
type="text/javascript">
function myAjax(){
var xmlhttp;
if(window.XMLHttpRequest){
xmlhttp = new XMLHttpRequest();
}else{
xmlhttp = ActionXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function(){
if (xmlhttp.readyState==4 && xmlhttp.status==200){
console.log(xmlhttp.responseText);
}
}
var url = "http://localhost:8080/minisns/json.jsp" + "?r=" + Math.random();
xmlhttp.open("Get",url,true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send();
}
>
>
>
|
这里为了结果不受其他js库的干扰,使用了原生的XMLHttpRequest来处理,结果如下:
我们看到8080端口的js的ajax请求无法访问8888端口的页面。原因是“同源策略不允许读取”。
既然普通的ajax不能访问,那么怎样才能访问呢?大家都知道,使用jsonp啊,那jsonp的原理是什么呢?他为什么能跨域呢?
@H_902_301@2.jsonp跨域的原理我们知道,在页面上有三种资源是可以与页面本身不同源的。它们是:js脚本,css样式文件,图片,像taobao等大型网站,很定会将这些静态资源放入cdn中,然后在页面上连接,如下所示,所以它们是可以链接访问到不同源的资源的。
1)<script type="text/javascript" src="某个cdn地址" ></script>
2)<link type="text/css" rel="stylesheet" href="某个cdn地址" />
3)<img src="某个cdn地址" alt=""/>
而jsonp就是利用了<script>标签可以链接到不同源的js脚本,来到达跨域目的。当链接的资源到达浏览器时,浏览器会根据他们的类型来采取不同的处理方式,比如,如果是css文件,则会进行对页面 repaint,如果是img 则会将图片渲染出来,如果是script 脚本,则会进行执行,比如我们在页面引入了jquery库,为什么就可以使用 $ 了呢?就是因为 jquery 库被浏览器执行之后,会给全局对象window增加一个属性: $ ,所以我们才能使用 $ 来进行各种处理。(另外为什么要一般要加css放在头部,而js脚本放在body尾部呢,就是为了减少repaint的次数,另外因为js引擎是单线程执行,如果将js脚本放在头部,那么在js引擎在执行js代码时,会造成页面暂停。)
@H_902_301@利用 页面上 script 标签可以跨域,并且其 src 指定的js脚本到达浏览器会执行的特性,我们可以进行跨域取得数据。我们用一个例子来说明:8888端口的html4项目中的jsonp.html页面代码如下:
>
>
>
type="text/javascript" src="js/jquery-1.11.1.js"></
type="text/javascript">
var url = "http://localhost:8080/html5/jsonp_data.js";
var script = document.createElement('script');
script.setAttribute('src',url);
document.getElementsByTagName('head')[0].appendChild(script);
function callbackFun(data)
{
console.log(data.age);
console.log(data.name);
}
>
>
其访问的8080端口的html5项目中的jsonp_data.js代码如下:
|