动态添加一个标签,而script标签的src属性是没有跨域的限制的。这样说来,这种跨域方式其实与ajax XmlHttpRequest协议无关了。
这样其实"jQuery AJAX跨域问题"就成了个伪命题,jquery $.ajax方法名有误导人之嫌。
如果设为dataType: 'jsonp',这个$.ajax方法就和ajax XmlHttpRequest没什么关系了,取而代之的则是JSONP协议。JSONP是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问。
JSONP即JSON with Padding。由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源。如果要进行跨域请求, 我们可以通过使用html的script标记来进行跨域请求,并在响应中返回要执行的script代码,其中可以直接使用JSON传递 javascript对象。 这种跨域的通讯方式称为JSONP。
Cross-Origin Resource sharing
这是W3C 新出的一个标准,简单的讲就是通过服务器/客户端 一些Headers的设置及确认 来实现跨域请求,这些包头有
Cross-Origin Resource sharing
这是W3C 新出的一个标准,简单的讲就是通过服务器/客户端 一些Headers的设置及确认 来实现跨域请求,这些包头有
例如
Access-Control-Allow-Origin: http://www.test.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: POWERED-BY-MENGXIANHUI
Access-Control-Max-Age: 30
可以参考 http://www.w3.org/TR/access-control/#access-control-allow-origin-response-header w3c的网站
1
2
3
4
5
6
7Access-Control-Allow-Origin: 允许跨域访问的域,可以是一个域的列表,也可以是通配符"*"。这里要注意Origin规则只对域名有效,并不会对子目录有效。
即http://www.test/test/是无效的。但是不同子域名需要分开设置,这里的规则可以参照那篇同源策略
Access-Control-Allow-Credentials: 是否允许请求带有验证信息,这部分将会在下面详细解释
Access-Control-Expose-Headers: 允许脚本访问的返回头,请求成功后,脚本可以在XMLHttpRequest中访问这些头的信息(貌似webkit没有实现这个)
Access-Control-Max-Age: 缓存此次请求的秒数。在这个时间范围内,所有同类型的请求都将不再发送预检请求而是直接使用此次返回的头作为判断依据,非常有用,大幅优化请求次数
Access-Control-Allow-Methods: 允许使用的请求方法,以逗号隔开
Access-Control-Allow-Headers: 允许自定义的头部,以逗号隔开,大小写不敏感
Access-Control-Allow-Credentials
在跨域请求中,默认情况下,HTTP Authentication信息,Cookie头以及用户的SSL证书无论在预检请求中或是在实际请求都是不会被发送的。
但是,通过设置XMLHttpRequest的credentials为true,就会启用认证信息机制。
虽然简单请求还是不需要发送预检请求,但是此时判断请求是否成功需要额外判断Access-Control-Allow-Credentials,如果Access-Control-Allow-Credentials为false,请求失败。
十分需要注意的的一点就是此时Access-Control-Allow-Origin不能为通配符"*"(真是便宜了一帮偷懒的程序员),如果Access-Control-Allow-Origin是通配符"*"的话,仍将认为请求失败
即便是失败的请求,如果返回头中有Set-Cookie的头,浏览器还是会照常设置Cookie
客户端页面test.php
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
crossDomainRequest
functioncreateXHR(){
returnwindow.XMLHttpRequest?
newXMLHttpRequest():
newActiveXObject("Microsoft.XMLHTTP");
}
functiongetappkey(url){
xmlHttp = createXHR();
xmlHttp.open("GET",url,false);
xmlHttp.send();
result = xmlHttp.responseText;
returnresult;
}
functioncrossDomainRequest(){
varcontent =getappkey('http://127.0.0.10/gettest.php');
document.getElementById("content").innerHTML=content;
}
服务端页面gettest.php
1
2
3
4
header("Access-Control-Allow-Origin: http://127.0.0.1");
echo"test success!";
?>
如果不允许的话
所以跨域有以下几种方法
通过webserver【nginx】配置来跨域
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#
# Wide-open CORS config for nginx
#
location / {
if($request_method ='OPTIONS') {
add_header'Access-Control-Allow-Origin''*';
#
# Om nom nom cookies
#
add_header'Access-Control-Allow-Credentials''true';
add_header'Access-Control-Allow-Methods''GET, POST, OPTIONS';
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header'Access-Control-Allow-Headers''DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header'Access-Control-Max-Age'1728000;
add_header'Content-Type''text/plain charset=UTF-8';
add_header'Content-Length'0;
return204;
}
if($request_method ='POST') {
add_header'Access-Control-Allow-Origin''*';
add_header'Access-Control-Allow-Credentials''true';
add_header'Access-Control-Allow-Methods''GET, POST, OPTIONS';
add_header'Access-Control-Allow-Headers''DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
if($request_method ='GET') {
add_header'Access-Control-Allow-Origin''*';
add_header'Access-Control-Allow-Credentials''true';
add_header'Access-Control-Allow-Methods''GET, POST, OPTIONS';
add_header'Access-Control-Allow-Headers''DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
}
示例代码
1
2
3
4
5
6
7
8
9
10location /{
add_header'Access-Control-Allow-Origin''http://www.test.com';
add_header'Access-Control-Allow-Credentials''true';
add_header'Access-Control-Allow-Methods''GET';
...
...
}
第一条指令:授权从http://www.test.com的请求
第二条指令:当该标志为真时,响应于该请求是否可以被暴露
第三天指令:指定请求的方法,可以是GET,POST等
如果需要允许来自任何域的访问,可以这样配置
1
Access-Control-Allow-Origin: *
通过后端程序来跨域
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
header("Access-Control-Allow-Origin:http://www.test.com");
header("Access-Control-Allow-Origin:*");
echojson_encode($_POST);
?>
$("#ajax").click(function(){
$.ajax({
type:"POST",
url:"http://www.test.com/test2.php",
data:'name=test',
dataType:"json",
success:function(data){
$('#Result').text(data.name);
}
});
});
JSONP
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
if(isset($_GET['name']) && isset($_GET['callback']))
//callback根js端要对应,不然会报错的
{
echo$_GET['callback'].'('. json_encode($_GET) . ');
}
?>
$("#jsonp").click(function(){
$.ajax({
url:'http://www.test.com/test1.php',
data: {name:'jsonp'},
dataType:'jsonp',
jsonp:'callback',//为服务端准备的参数
jsonpCallback:'getdata',//回调函数
success:function(){
alert("success");
}
});
});
functiongetdata(data){
$('#Result').text(data.name);
}
getJSON
1
2
3
4
5
6
7
8
$("#getjson").click(function(){
$.getJSON('http://www.test.com/test1.php?name=getjson&callback=?',function(data){
//没有回调函数,直接处理
$('#Result').text(data.name);
})
})
getScript
1
2
3
4
5
$("#getscript").click(function(){
$.getScript('http://www.test.com/test1.php?name=getscript&callback=getdata');
});