博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
AJAX 跨源 HTTP 请求
阅读量:5141 次
发布时间:2019-06-13

本文共 5056 字,大约阅读时间需要 16 分钟。

AJAX 跨源 HTTP 请求

来源: 发布时间:2014-04-30 阅读次数:1700
 
提示:常上QQ空间的朋友可关注 ,精彩内容不错过。

 背景

  跨源HTTP请求(也称跨域AJAX请求)是大多数Web开发人员可能遇到的一个问题,根据,浏览器将限制客户端的JavaScript在一个安全沙箱内,通常JS不能直接同一台不同的域的远程服务器通信。在过去,开发者们创造了许多解决方法以实现跨域资源请求,常用的方法如下:

  1. 使用Flash/Silverlight或服务器端“代理”来与远程通讯 

  2. ).

  3. 在iframe中嵌入远程服务器并通过fragment或window.name通信,参考这里。

  如此等等..

  这些解决方法或多或少都有问题,比如使用JSONP时若只是简单的“eval”将导致安全漏洞,#3虽然能用,但两个域间必须依据严格的协议,恕我直言它既不灵活也不优雅

  W3C已经引入了作为能够解决该问题并提供安全、灵活以及推荐标准的解决方案。

 机制

  从较高的层次来看我们可以简单认为CORS 是介于 域A客户端 的AJAX调用 和一个托管在域B的页面 之间的契约, 一个典型的跨源 请求或者响应将会是这样:

  域 A 的 AJAX 请求头

Host DomainB.com  

User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0  
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,application/json  
Accept-Language en-us;  
Accept-Encoding gzip, deflate  
Keep-Alive 115  
 Origin 

  域 B 的 响应头

Cache-Control private /> Content-Type application/json; charset=utf-8  

 Access-Control-Allow-Origin DomainA.com  
Content-Length 87  
Proxy-Connection Keep-Alive  
Connection Keep-Alive

  我上面标记的蓝色部分是关键实现, "Origin" 请求头表示  或者  源于哪里,  "Access-Control-Allow-Origin" 请求头 表示这个页面允许来自域A 的请求(其值为 * 表示允许任何域的远程请求)。

  像我上面提到的,W3 建议浏览器在提交实际跨源HTTP 请求前,实现“预检请求”, 简而言之,就是一个HTTP OPTIONS 请求:

OPTIONS DomainB.com/foo.aspx HTTP/1.1

  如果 foo.aspx 支持 OPTIONS HTTP 指令, 它可能会像下面这样返回响应:

HTTP/1.1 200 OK  

Date: Wed, 01 Mar 2011 15:38:19 GMT  
Access-Control-Allow-Origin:     
Access-Control-Allow-Methods: POST, GET, OPTIONS, HEAD  
Access-Control-Allow-Headers: X-Requested-With  
Access-Control-Max-Age: 1728000  
Connection: Keep-Alive  
Content-Type: application/json

  只有满足在响应中包含 "Access-Control-Allow-Origin" , 并且其值为 "*" 或者包含提交CORS请求的域,这些强制条件的浏览器才能提交正式的跨域请求, 并在 ” 中缓存请求结果 。

 实现

  让我们看一下服务器端代码,例子如下(ASP.NET和PHP)

  ASP.NET (C#)

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
protected
void
Page_Load(
object
sender, EventArgs e)
 
{
     
String data = String.Empty;
     
String returnJSONStr = String.Empty;
  
     
switch
(Request.HttpMethod)
     
{
         
case
"GET"
:
             
data = Request.QueryString[
"Data"
];
             
returnJSONStr =
"{\"Data\":\"Hi remote friend, you tried to passed me data: *"
+ data +
"* through HTTP GET.\"}"
;
             
break
;
         
case
"POST"
:
             
data = Request.Form[
"Data"
];
             
returnJSONStr =
"{\"Data\":\"Hi remote friend, you tried to POST some mock data: *"
+ data +
"* to me.\"}"
;
             
break
;
         
case
"OPTIONS"
:
             
break
;
         
default
:
             
returnBadRequestResponse();
             
break
;
     
}
  
     
if
(String.IsNullOrEmpty(data))
         
returnBadRequestResponse();
     
else
     
{
         
Response.AddHeader(
"Access-Control-Allow-Origin"
,
"*"
);
         
Response.ContentType =
"application/json"
;
         
Response.Write(returnJSONStr);
     
}
 
}
  
 
private
void
returnBadRequestResponse()
 
{
     
Response.StatusCode = 400;
     
Response.ContentType =
"application/json"
;
     
Response.Write(
"{\"Error\":\"Bad HTTP request type!\"}"
);
 
}

  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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
if
(isset($[
"Data"
]))
 
{
     
$method
=
$_SERVER
['REQUEST_METHOD'];
     
$data
=
""
;
     
if
(
$method
==
"POST"
)
     
{
         
$data
=
$_POST
[
"Data"
];
  
         
$fakeData
=
new
FakeData();
         
$fakeData
->Data=
"Hi remote friend, you tried to POST some mock data: *"
+data+
"* to me."
;
         
$fakeData
->Time=
new
DateTime(
"now"
);
     
}
     
elseif
(
$method
==
"GET"
)
     
{
         
$fakeData
=
new
FakeData();
         
$fakeData
->Data=
"Hi remote friend, you tried to passed me data: *"
+data+
"* through HTTP GET."
;
         
$fakeData
->Time=
new
DateTime(
"now"
);
     
}
     
else
     
{
         
RaiseError();
     
}
  
     
header('Content-type: application/json');
     
$jsonStr
= json_encode(
$fakeData
);
     
echo
(
$jsonStr
);
 
}
 
else
 
{
     
RaiseError();
 
}
  
 
function
RaiseError()
 
{
     
http_send_status(405);
     
header(
"Status: 405 Method Not Allowed"
);
 
}
  
 
/*Classes definition*/
 
class
FakeData
 
{
     
public
$Data
;
     
public
$Time
;
 
}

  客户端AJAXY发起请求代码:

 

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
var
cor =
null
;
// cor stands for Cross-Origin request
  
 
if
(window.XMLHttpRequest) {
     
cor =
new
XMLHttpRequest();
 
}
 
//else if (window.XDomainRequest) {
     
//cor = new XDomainRequest();
 
//}
 
else
{
     
alert(
"Your browser does not support Cross-Origin request!"
);
     
return
;
 
}
  
 
cor.onreadystatechange =
function
() {
     
if
(cor.readyState == 4) {
         
document.getElementById('lbl').innerHTML = cor.responseText;
     
}
 
};
  
 
var
data = 'Some fake data';
 
if
(method == 'POST') {
     
cor.open('POST', 'http:
//WayneYe.com/Demo/CORSDemo/CORSDemoServer.aspx', true);
     
cor.withCredential =
"true"
;
     
cor.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
     
cor.send('Data=' + data);
 
}
 
else
if
(method == 'GET') {
 
     
cor.open('GET', 'http:
//WayneYe.com/Demo/CORSDemo/CORSDemoServer.aspx?Data=' + data, true);
     
cor.withCredential =
"true"
;
     
cor.send(
null
);
 
}

  JS代码适用于所有主流浏览器(IE8+, FF 3.6+, Chrome 8+),我没有用IE8所采用的XDomainObject,因为 IE8+, FF and Chrome, Safari等浏览器支持XMLHTTP请求。而且XDomainObject(XDR)似乎有很多限制(参考: )

 结论

  跨源资源共享为网站开发人员实现跨源通信提供了一个安全,灵活,标准的方案。也许是时候摈弃像JSONP,Flash,Silverlight,server bridge以及window.name等等并不是很实用的方法。

转载于:https://www.cnblogs.com/rubyxie/articles/3817701.html

你可能感兴趣的文章
CSS3 动画-- 鼠标移上去,div 会旋转、放大、移动
查看>>
理解MapReduce
查看>>
2019春第四周作业
查看>>
92. Reverse Linked List II
查看>>
SpringBoot非官方教程 | 第二十四篇: springboot整合docker
查看>>
PostgreSQL学习笔记——窗口函数
查看>>
【linux】16进制格式查看命令hexdump
查看>>
线程同步
查看>>
BZOJ2423: [HAOI2010]最长公共子序列
查看>>
java中读取文本文件的时候@Test方法中没有中文乱码,但是@Controller中却有中文乱码...
查看>>
Sublime Text插件推荐
查看>>
浅谈BloomFilter【上】基本概念和实现原理
查看>>
css滑动鼠标到img后,切换图片
查看>>
java长连接socket【转】http://jiewo.iteye.com/blog/1562168
查看>>
NSAssert和NSParameterAssert
查看>>
浮点数规格化-不同基数的规格化
查看>>
Hibernate初探之单表映射——第二章:Hibernate进阶
查看>>
TomCat服务器闪退问题
查看>>
c#中跨线程访问
查看>>
8.1 H5 智能标签
查看>>