在认识 跨域 之前,先简单了解下域名和协议名,比如下面这个 URL
http://mail.163.com/index.html
http:// 协议名,也就是HTTP超文本传输协议
mail 服务器名
163.com 域名
mail.163.com 网站名
/ 根目录
index.html 根目录下的默认网页
1、什么是跨域请求?
请求的下一个资源所在的 协议、域名、端口号 三者之一与当前资源不一致就称为 跨域请求
简单理解,就是 $.get(url, [data], [callback], [type]) 里面的 url 的协议名、域名 或者 端口号与当前域名不一样
为了避免晦涩难懂的文字,我们直接上一个小 demo:
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
|
<!DOCTYPE html>
<
html
>
<
head
lang
=
"en"
>
<
meta
charset
=
"UTF-8"
>
<
title
></
title
>
</
head
>
<
body
>
<
h2
>非跨域请求</
h2
>
<
button
id
=
"btn1"
>非跨域按钮</
button
>
<
h2
>跨域请求</
h2
>
<
button
id
=
"btn2"
>跨域按钮</
button
>
<
script
src
=
"//cdn.bootcss.com/jquery/3.1.1/jquery.js"
></
script
>
<
script
>
$('#btn1').click(function(obj){
$.get('http://localhost:8081/Ajax/2.php',function(){
console.log('btn1被单击后发起的XHR请求');
console.log(obj);
})
})
$('#btn2').click(function(obj){
$.get('http://dapengtalk.blog.51cto.com/',function(){
console.log('btn2被单击后发起的XHR请求');
console.log(obj);
})
})
</
script
>
</
body
>
</
html
>
|
在浏览器地址栏输入“http://localhost:8081/Ajax/cross.html”打开页面,点击“非跨域按钮”,查看控制台
点击“跨域按钮”,查看控制台,发现 XHR请求失败了,很明显,请求的域名不同,这就是典型的跨域
查看 Network,XHR请求发起了,而且状态码是200
查看请求头部消息,显示有 24 字节的响应消息
查看响应消息,却显示“这个请求没有可用的响应消息”
2、浏览器允许 跨域请求吗?
允许:<img src="跨域的图片">
允许:<link rel="stylesheet" href="跨域的CSS">
允许:<a href="跨域的链接">
允许:<script src="跨域的JS">
禁止:AJAX请求是不允许跨域的!
说明:出于安全考虑,所有的浏览器默认都禁止使用XHR异步的跨域请求。
举个例子,比如上面提到的 img 允许跨域
1
2
3
4
5
6
7
8
9
10
11
12
|
<!DOCTYPE html>
<
html
>
<
head
lang
=
"en"
>
<
meta
charset
=
"UTF-8"
>
<
title
></
title
>
</
head
>
<
body
>
<
img
src
=
"https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png"
alt
=
"百度logo"
>
</
body
>
</
html
>
|
不同协议名、不同域名,网页正常显示图片,说明允许跨域。但是文章一开始的 demo 中,使用 Ajax 发起异步请求的时候,却是不被允许的。那该怎么办呢?
3、跨域 解决方案
3-1、设置“Access-Control-Allow-Origin”头部
还记得吗?域名和域名对应的ip 也是不允许跨域的,在此基础上,我们把上面的例子稍作修改:
(尽管是同一个 2.php 页面,但一个是域名,一个是域名对应的ip)
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
|
<!DOCTYPE html>
<
html
>
<
head
lang
=
"en"
>
<
meta
charset
=
"UTF-8"
>
<
title
></
title
>
</
head
>
<
body
>
<
h2
>非跨域请求</
h2
>
<
button
id
=
"btn1"
>非跨域按钮</
button
>
<
h2
>跨域请求</
h2
>
<
button
id
=
"btn2"
>跨域按钮</
button
>
<
script
src
=
"//cdn.bootcss.com/jquery/3.1.1/jquery.js"
></
script
>
<
script
>
$('#btn1').click(function(obj){
$.get('http://localhost:8081/Ajax/2.php',function(){
console.log('btn1被单击后发起的XHR请求');
console.log(obj);
})
})
$('#btn2').click(function(obj){
$.get('http://127.0.0.1:8081/Ajax/2.php',function(){
console.log('btn2被单击后发起的XHR请求');
console.log(obj);
})
})
</
script
>
</
body
>
</
html
>
|
PHP代码:
1
2
3
4
5
6
7
|
<?php
header(
'Content-Type: application/json; charset=utf8'
);
$data
= [
'uname'
=>
'Tom'
,
'age'
=>20];
echo
json_encode(
$data
);
|
点击“非跨域按钮“,可以正常发起 Ajax 请求
点击“跨域按钮”,报错了,说明这个属于 跨域
按照控制台给出的提示,我们在 php 页面中设置 Access-Control-Allow-Origin 头部
PHP代码:
1
2
3
4
5
6
7
8
9
10
|
<?php
header(
'Content-Type: application/json; charset=utf8'
);
// 指定允许其他域名访问
header(
'Access-Control-Allow-Origin:*'
);
$data
= [
'uname'
=>
'Tom'
,
'age'
=>20];
echo
json_encode(
$data
);
|
看到 btn2,真是太难得了,这个也就说明 设置 Access-Control-Allow-Origin 头部 是可以解决跨域的
3-2、使用 JSONP
基于3-1的示例代码,我们再来看一个例子:
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
|
<!DOCTYPE html>
<
html
>
<
head
lang
=
"en"
>
<
meta
charset
=
"UTF-8"
>
<
title
></
title
>
</
head
>
<
body
>
<
button
id
=
"crossBtn"
>跨域按钮</
button
>
<
script
src
=
"//cdn.bootcss.com/jquery/3.1.1/jquery.js"
></
script
>
<
script
>
function doResponse(obj){
alert(obj.uname+obj.age);
}
$('#crossBtn').click(function(){
$.ajax({
url:'http://127.0.0.1:8081/Ajax/3.php',
success:doResponse
})
})
</
script
>
</
body
>
</
html
>
|
PHP代码:
1
2
3
4
5
6
7
8
|
<?php
header(
'Content-Type: application/json'
);
$data
= [
'uname'
=>
'Tom'
,
'age'
=>20];
$json
= json_encode(
$data
);
//返回一个json{"":"","":20}'
echo
'doResponse('
.
$json
.
')'
;
|
通过浏览器输入“http://localhost:8081/Ajax/jsonp01.html”打开网页,这是一个典型的跨域请求,这里可以使用JSONP手段来解决
在$.ajax 方法中有一个 dataType属性,如果将该属性设置成 dataType:"jsonp",就能实现跨域
把上面的代码稍作修改:
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
|
<!DOCTYPE html>
<
html
>
<
head
lang
=
"en"
>
<
meta
charset
=
"UTF-8"
>
<
title
></
title
>
</
head
>
<
body
>
<
button
id
=
"crossBtn"
>跨域按钮</
button
>
<
script
src
=
"//cdn.bootcss.com/jquery/3.1.1/jquery.js"
></
script
>
<
script
>
function doResponse(obj){
alert(obj.uname+obj.age);
}
$('#crossBtn').click(function(){
$.ajax({
url:'http://127.0.0.1:8081/Ajax/3.php',
dataType:'jsonp',
success:doResponse
})
})
</
script
>
</
body
>
</
html
>
|
PHP代码:
1
2
3
4
5
6
7
8
|
<?php
header(
'Content-Type: application/javascript'
);
$data
= [
'uname'
=>
'Tom'
,
'age'
=>20];
$json
= json_encode(
$data
);
//'{"":"","":20}'
echo
'doResponse('
.
$json
.
')'
;
|
重新打开页面,可以拿到数据了
如果想更深入的了解 JSONP 原理,可以查看另一篇文章 《详解 JSON 和 JSONP》
http://dapengtalk.blog.51cto.com/11549574/1877684