微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

逐渐深入地理解Ajax

Ajax的基本原理是:XMLHttpRequest对象(简称XHR对象),XHR为向服务器发送请求和解析服务器响应提供了流畅的接口。能够以异步方式从服务器获得更多信息。意味着用户不必刷新页面也能取得新数据,然后通过DOM将数据插入到页面中。

XMLHttpRequest对象方法如下:

about():停止当前的请求;

open(“method”,”URL”,[asyncFlag]):

等常见的方法

XHR的基本用法

在使用XHR对象时,要调用的第一个方法open()方法,它有三个参数,第一个参数是:需要发送请求的类型(get或者post),第二个参数是请求的url,第三个参数是请求的布尔值(true是异步,false是同步);

xhr.open(‘get’,'http://127.0.0.1/ajax/ajax.PHP’,false);

如上代码会启动一个get请求ajax.PHP,但是请注意:open方法并不会真正发请求,而只是启动一个请求以备发送;

要发送真正请求必须使用send()方法;如下:

xhr.send(null);

send的方法接收一个参数,需要请求发送的数据,如果请求不需要发送数据,需要传送一个null,因为对于有些浏览器这是必须的;上面第三个参数传的是false,是同步请求,服务器接收到响应后再继续执行后面的代码,响应后的数据会自动填充XHR对象的属性,XHR有以下属性

responseText: 作为响应主体被返回的文本。

responseXML: 如果响应的内容是”text/xml” 或 “application/xml”,这个属性将保存包含响应数据的XML DOM文档;

status: 响应http状态;

statusText: http状态说明;

在接收到响应后,第一步是检查status状态,如果状态时200,说明已经成功返回,此时responseText属性已经就绪;如果状态是304,说明资源未被修改,可以直接使用浏览器缓存的版本,当然,响应是有效的;如下ajax请求代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 创建xhr对象方法如下:
function createXHR(){
var xhr;
if (window.XMLHttpRequest){
// code for IE7+,Firefox,Chrome,Opera,Safari
xhr= new XMLHttpRequest();
} else { // code for IE6,IE5
ActiveXObject( "Microsoft.XMLHTTP" );
}
return xhr;
}
xhr = createXHR();
xhr.open( 'get' , 'http://127.0.0.1/ajax/ajax.PHP' false );
xhr.send( null );
((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
console.log(xhr.responseText);
{
console.log(xhr.status);
}

ajax.PHP代码如下:

4
<?PHP
$data = json_decode(file_get_contents( "PHP://input" ));
echo ( '{"id" : ' . $data->id . ',"age" : 24,"sex" : "boy","name" : "huangxueming"}' );
?>

发ajax请求后,在控制台中打印如下:

说明已经请求成功;

上面的demo代码是同步请求,但是有时候我们需要发送异步请求,才能让javascript后续代码继续执行而不会堵塞,此时,我们可以检测XHR对象的readyState属性,该属性表示请求/响应当前活动阶段;这个属性取值如下:

0:未初始化。尚未调用open()方法

1:启动。已经调用open()方法,但未调用send()方法

2:发送。已经调用send()方法,但尚未接收到响应;

3:接收。已经接收到部分数据;

4:完成。已经接收到全部响应数据,而且可以在客户端使用了;

readyState属性值由一个值变为另一个值,就会触发一次readystatechange事件。可以利用这个事件检测每次状态变化后的readyState值,但是必须在调用open()方法之前指定onreadystatechange事件;如下代码

19
20
21
22
23
24
(window.XMLHttpRequest){
{
);
}
xhr;
}
xhr = createXHR();
xhr.onreadystatechange = (){
(xhr.readyState == 4) {
((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
console.log(xhr.responseText);
{
console.log(xhr.status);
}
}
}
);
);

如上代码,在处理onreadystatechange事件时使用了xhr对象,没有使用this对象,原因是onreadystatechange事件处理程序的作用域的问题;如果使用this对象,在有的浏览器下会执行失败,或者导致错误发生;

理解Http头部信息

每个http请求和响应都会带有响应的头部信息,xhr对象也提供了操作这两种头部(请求头部和响应头部的)信息的方法

认情况下,在发送XHR请求的同时,还会发送下列头部信息

Accept: 浏览器能够处理的内容类型;

Accept-Charset: 浏览器能够显示的字符集;

Accept-Encoding: 浏览器能够处理的压缩编码;

Accept-Language: 浏览器当前设置的语言;

Connection: 浏览器与服务器之间连接的类型;

Cookie:当前页面设置的cookie;

Host:发出请求页面所在的域;

Referer:发出请求的页面url。

User-Agent: 浏览器的用户代理字符串。

如下ajax.PHP请求所示:

我们还可以使用setRequestHeader()方法可以设置自定义的请求头部信息,这个方法接收2个参数:头部字段的名称和头部字段的值;要成功发送请求头部信息,必须在调用open()方法之后且调用send()方法之前调用setRequestHeader();如下demo所示:

5
);
xhr.setRequestHeader( "myHeader" "myValue" );
截图如下:

调用getAllResponseHeaders()方法则可以取得一个包含所有头部信息的长字符串,如上代码中在onreadystatechange事件中添加getAllResponseHeaders()方法

9
(){
(xhr.readyState == 4) {
((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
myHeader = xhr.getAllResponseHeaders();;
console.log(myHeader);
{
console.log(xhr.status);
}
打印如下:

理解GET请求

在ajax中,有常见的get请求或者post请求,使用get请求时,我们是把参数的名-值对经过encodeURIComponent()进行编码,然后放到URL的末尾,所有名值对必须由和好(&)分割;如下代码

1
'http://127.0.0.1/ajax/ajax.PHP?name1=value1&name2=value2'
true 下面我们可以封装一个方法可以辅助向现有的URL的末尾添加查询字符串参数;

addURLParam(url,name,value) {
url += url.indexOf( "?" ) == -1 ? : "&" ;
url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
url;
如下代码测试:

24
25
26
27
28
29
30
31
32
33
(window.XMLHttpRequest){
XMLHttpRequest();
);
}
xhr;
}
xhr = createXHR();
(){
(xhr.readyState == 4) {
((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
myHeader = xhr.getAllResponseHeaders();;
console.log(myHeader);
}
url = "http://127.0.0.1/ajax/ajax.PHP" ;
url = addURLParam(url,monospace!important; bottom:auto!important; float:none!important; height:auto!important; left:auto!important; line-height:1.1em!important; outline:0px!important; overflow:visible!important; position:static!important; right:auto!important; top:auto!important; vertical-align:baseline!important; width:auto!important; min-height:auto!important; color:blue!important">"name1" "value1" );
"name2" "value2" );
);
);
);
;
+ encodeURIComponent(value);
url;
如下截图所示:

理解POST请求:

Post请求时作为请求的主体提交,post请求的主体可以是非常多的数据,而且格式不限;在open方法的第一个参数传入post,就可以初始化post请求,如下:xhr.open(‘post’,”http://127.0.0.1/ajax/ajax.PHP”,true);

接下来我们需要使用send()方法来发送数据,传入的参数可以是任何的字符串或者form表单序列化之后的数据;比如我们现在可以使用xhr来模仿表单提交数据,首先我们需要将Content-Type头部信息设置为application/x-www-form-urlencoded,也就是表单提交的内容类型,其次以适当的格式创建一个字符串,比如form表单序列化数据,然后通过xhr发送到服务器端,

如下HTML代码

4
<form id=
"form" >
<input name= "user-name" value= "aaa" />
"user-email" "233" />
</form>

JS代码如下:

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
// 序列化的代码
serialize(form) {
arrs = [],
field = i,
len,
j,
optLen,
option,
optValue;
for (i = 0,len = form.elements.length; i < len; i++) {
field = form.elements[i];
switch (field.type) {
case "select-one" :
"select-multiple" :
(field.name.length) {
(j = 0,optLen = field.options.length; j < optLen; j++) {
option = field.options[j];
(option.selected) {
optValue = '' ;
(option.hasAttribute) {
optValue = option.hasAttribute( "value" ) ? option.value : option.text;
{
optValue = option.attributes[ ].specified ? option.value : option.text;
}
arrs.push(encodeURIComponent(field.name) + +encodeURIComponent(optValue));
}
}
}
break case undefined: //字段集
"file" : // 文件输入
"submit" // 提交按钮
"reset" // 重置按钮
"button" // 自定义按钮
;
"radio" // 单选框
"checkBox" // 复选框
(!field.checked) {
;
}
/* 执行认动作 */
default :
// 不包含没有名字的表单字段
(field.name.length) {
+encodeURIComponent(field.value));
}
}
}
arrs.join( );
}
;
'post' );
"Content-Type" "application/x-www-form-urlencoded" );
form = document.getElementById( );
xhr.send(serialize(form));

之后我们可以看到form表单序列化之后传过去的数据如下:

XMLHttpRequest 2级

XMLHttpRequest 1级只是把已有的xhr对象的实现细节描述出来了,而XMLHttpRequest 2级是在原来的基础上增加了一些规范,但所有的浏览器只是实现了他规定的部分内容;如下几个:

理解FormData

现在web应用中频繁使用的一项功能是form表单序列化,XMLHttpRequest 2级定义了FormData类型,使用FormData获取数据与表单序列化数据一样,但是更简洁方便;

支持FormData浏览器有:firefox4+,safari5+,chrome和Android3+版的webkit.

比如我现在提交form表单数据如下demo:

HTML代码

;
);
FormData(form));

在chrome浏览器下如下:

在firefox浏览器如下:

使用formData的方便之处体现在不必明确地在XHR对象上设置请求头部,XHR对象能识别传入的数据类型是FormData实例,并配置适当的头部信息

理解超时设定

IE8为XHR对象添加一个timeout属性,表示请求在等待响应多少毫秒之后停止,在给timeout设置一个数值后,如果在规定的时间之内浏览器没有接受到响应,那么就会触发ontimeout事件,那么就会终止ajax请求,如下代码

7
);
xhr.timeout = 1;
xhr.ontimeout = (){
alert( "111" );
};
如上我把代码timeout设置1毫秒,如果请求1毫秒之后没有返回数据的话,就执行ontimeout事件,并且请求停止掉,目前我测试的浏览器chrome和firefox都支持;如下chrome浏览器截图如下:

进度事件

Progress Events规范是W3C的一个工作草案,定义了与客服端服务器通信有关的事件,这些事件最早是针对XHR操作的,有以下6个事件;

loadstart: 在接收到响应数据的第一个字节时触发;

progress: 在接收响应期间持续不断的触发;

error: 在请求发生错误时触发;

abort: 在因为调用abort()方法而终止连接时触发;

load:在接收到完整的响应数据时触发;

loadend:在通信完成或者触发error,abort或load事件后触发;(这个事件基本上不使用的。)

支持前5个事件的浏览器有:firefox3.5+,safari4+,chrome,IOS版的safari和android版的webkit,opera(从11开始),IE8+只支持load事件;

load事件

Firefox在实现XHR对象的某个版本时,为了简化异步交互模型,实现了load事件,用以替代readystatechange事件,响应接收完毕后触发load事件,因此就没有必要检查readyState属性了;

目前支持的浏览器有:firefox,opera,chrome和safari

如下代码演示:

10
xhr = createXHR();
xhr.onload = (){
console.log(xhr.responseText);
{
console.log(xhr.status);
}
);
progress事件

这个事件在浏览器接收数据期间周期性的触发,而onprogress事件处理程序会接收一个event对象,包含三个属性,lengthComputable是一个表示进度信息是否可用的布尔值;position表示已经接收的字节数,totalSize表示根据Content-Length响应头部确定的预期总字节数。如下代码

17
xhr.onprogress =
(event) {
divstatus = document.getElementById( "status" );
(event.lengthComputable){
divstatus.innerHTML = "Received " + event.position + " of " +
event.totalSize + " bytes" ;
}
};
);
截图运行如下:

跨源资源共享

通过XHR实现ajax通信的一个主要限制,来源于跨域安全策略。认情况下,XHR对象只能访问与包含它的页面位于同一个域中的资源,因为浏览器这样做的限制就是防止一些恶意操作;那么CORS(跨源资源共享)的基本原理是:需要由服务器发送一个响应标头就可以让浏览器与服务器进行沟通;

比如我现在做一个demo来试着看,假如我现在在hosts文件下绑定2个IP地址:如下:

127.0.0.1 abc.example1.com

127.0.0.1 def.example2.com

那么现在我 abc.example1.com下有一个页面ajax.html,如下代码

(){
'POST' "http://def.example2.com/ajax/ajax.PHP" 如上代码,在给域下def.example2.com 下的ajax.PHP发ajax请求,因为是同源策略问题,肯定不成功,如下所示:

现在我们在def.example2.com域下PHP设置头部即可;如下代码

header(“Access-Control-Allow-Origin: *”);

5 header( "Access-Control-Allow-Origin: *" );
));
);
这样就可以认为大功告成,很高兴,看到书上或者网上查找资料后,也是这么说的,但是呢 当我再次请求这个页面的时候http://abc.example1.com/ajax/ajax.html还是发现因为同源策略的问题,请求不成功,查看控制台这样的错误,如下:

1 XMLHttpRequest cannot load http: //def.example2.com/ajax/ajax.PHP. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://abc.example1.com' is therefore not allowed access.

也是同源策略的问题,不允许访问;继续通过网上查找资料,发现原来是我的PHP.ini里面的配置出了问题,在PHP安装目录下找到PHP.ini文件output_buffering认为off的。我现在把它设为on就OK了。如下截图所示:

我们继续重启下PHP服务器,即可看到请求成功,这时候我们会喜出往外;这时候我们再看看PHP请求如下设置:

PHP文件头部设置header,header(“Access-Control-Allow-Origin: *”);星号意思是所有的请求都可以,但是设置并不安全,所以我们可以针对当前的这个页面域下设置,如下:

5
"Access-Control-Allow-Origin: http://abc.example1.com" 我们继续截图如下看看:

同样也可以访问;但是上面的在IE7-8下还是会报错,因为同源策略的问题,会报错,如下截图所示:

标准浏览器下比如chrome或者firefox不会报错,那么我们可以看下在IE下,IE如何实现对CORS的支持

IE对CORS的实现方式如下:

微软在IE中引入XDR(XDomainRequest)类型,这个对象与XHR类似,但是能实现安全可靠的跨域通信,XDR对象部分实现了W3C的CORS规范;XDR与XHR不同之处如下:

  1. Cookie不会随请求发送,也不会随响应返回。
  2. 只能设置请求头部信息中的Content-Type字段。
  3. 不能访问响应头部信息
  4. 支持get和post请求。

这些变化使CSRF(Cross-Site Request Forgery,跨站点请求伪造)和XSS(Cross-Site Scripting,跨站点脚本)的问题得到了缓解,被请求的资源可以根据它认为合适的任意数据(用户代理,来源页面等)来决定是否设置Accept-Control-Allow-Origin头部。作为请求的一部分,Origin头部的值表示请求的来源域,以便远程资源明确地识别XDR请求。

XDR对象的使用方法与XHR对象非常相似,先创建一个XDomainRequest对象,如下:

var xdr = new XDomainRequest();

调用open()方法,再调用send()方法;但是XDR对象的open()方法只接受2个参数,请求的类型和URL;

所有XDR的请求都是异步的,不能用来创建同步请求,请求成功后,会触发load事件,响应的数据保存在responseText属性中;如下demo,我们继续看下在IE7-8下如何可以跨域请求成功;如下代码

6
xdr = XDomainRequest();
xdr.onload = () {
alert(xdr.responseText);
};
xdr.open( xdr.send( 现在我们刷新下页面可以看到请求成功了,如下所示:

如果响应失败的话,会调用error方法通知开发人员,如下代码

xdr.onerror = (){
"响应失败" );
};
);
与XHR一样,XDR对象也支持timeout属性以及ontimeout事件处理程序,如下代码

xdr.timeout = 1;
xdr.ontimeout = "Request took too long." };

请求超过1毫秒后没有响应,就调用ontimeout事件;

标准浏览器下实现对CORS的实现

其实实现方式在第一次讲解跨域的时候我们已经讲过了,可以翻到上面,但是我们现在重新来理一遍;

Firefox3.5+,Safari4+,chrome,ios版的safari和android平台中的webkit都通过XMLHttpRequest对象实现了CORS的原生支持;如下代码

12
xhr =
XMLHttpRequest();
(xhr.readyState == 4){
((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
alert(xhr.responseText);
}
}
);
如上代码即可就可以实现在标准浏览器下ajax的跨域通信问题;

与IE中的XDR对象不同,通过跨域XHR对象可以访问status和statusText属性,而且还支持同步请求,跨域XHR对象也有一些限制,如下限制:

  1. 不能使用setRequestHeader()设置自定义头部;
  2. 不能发送和接收cookie。
  3. 调用getAllResponseHeaders()方法总会返回空字符串。

跨浏览器的CORS的实现

如上介绍的是对IE下和标准浏览器下2种方案实现跨域的实现方案,下面我们可以来封装下对常用的所有浏览器支持下,首先我们先检查是否存在withCredentials属性(标准浏览器下有这个属性),再结合检测XDomainRequest对象是否存在(就可以检测到IE),如下是所有封装的代码

createCORSRequest(method,url) {
XMLHttpRequest();
( "withCredentials" in xhr) {
xhr.open(method,monospace!important; bottom:auto!important; float:none!important; height:auto!important; left:auto!important; line-height:1.1em!important; outline:0px!important; overflow:visible!important; position:static!important; right:auto!important; top:auto!important; vertical-align:baseline!important; width:auto!important; min-height:auto!important">);
else if ( typeof XDomainRequest != 'undefined' ) {
xhr = XDomainRequest();
{
;
xhr;
}
request = createCORSRequest( );
(request) {
request.onload = (){
alert(request.responseText);
}
request.send();
浏览器支持程度:IE7+,firefox3.5+,safari4+,chrome3+等;

JSONP跨域技术的基本原理

Jsonp跨域get请求是如何实现的;我们先来了解下为什么会出现跨域?

Javascript是一种在web开发中经常使用的前端动态脚本技术,在javascript中,有一个很重要的安全限制,被称为”same-Origin-Policy”同源策略,这一策略对于javascript代码能够访问的页面内容作了很重要的限制,即javascript只能访问与包含它的文档在同一域下的内容

JSONP的基本原理是:利用在页面中创建<script>节点的方法向不同域提交http请求的方法称为JSONP。

比如我现在的ajax.html页面http://abc.example1.com/ajax/ajax.html 下提交ajax请求http://def.example2.com/ajax/ajax.phpget请求,我们可以在ajax.html页面动态的创建script标签,如下:

eleScript= document.createElement( "script" );
eleScript.type = "text/javascript" ;
eleScript.src = ;
document.getElementsByTagName( "HEAD" )[0].appendChild(eleScript);

当get请求从http://def.example2.com/ajax/ajax.php返回时,可以返回一断javascript代码,这段代码自动执行,可以用来负责调用页面http://abc.example1.com/ajax/ajax.html中的一个callback函数

理解JSONP执行过程如下:

首先在客户端注册一个callback(比如jsonpcallback),然后把callback名字(比如叫jsonp123456)传给服务器端,服务器端得到callback名字后,需要用jsonp123456()把将要输出的json内容包括起来,此时,服务器生成的json数据才能被客户端正确接收;然后以javascript语法的方式,生成一个function,function的名字就是传递回来的参数jsonp123456.然后就可以在客户端直接运行调用jsonp123456这个函数了;

JSONP的优点:它不像XMLHttpRequest对象实现ajax请求受到同源策略的限制,它在所有的浏览器都支持,比如古老的IE6也支持,并且在请求完成后可以通过callback的方式传回结果;

JSONP的缺点:支持get请求,不支持post请求,它只支持http跨域的请求情况,不能解决不同域的两个页面之间如何进行javascript调用的问题;

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


IE6是一个非常老旧的网页浏览器,虽然现在很少人再使用它,但是在某些特殊情况下,我们可能还需要使用IE6来访问网页。而在IE6中,我们通常会使用JavaScript来提交表单,来看一下具体操作。
PHP中的count()函数是用来计算数组或容器中元素的个数。这个函数十分方便,在编写代码时使用频率也非常高。无论你是要统计数组的长度、统计字符串中字符出现的次数还是统计对象中属性的个数,count()都可以帮助你轻松
使用 AJAX(Asynchronous JavaScript and XML)技术可以在不刷新整个页面的情况下,向服务器发送请求并接收响应。通常来说,我们使用 AJAX 请求是为了获取后台数据,并将其展示在前端页面上。然而,有时候我们只需要
Ajax(Asynchronous JavaScript and XML)是一种用于改进网页用户体验的技术,通过与服务器进行异步通信,实现在网页上局部刷新数据而不必整个页面刷新的功能。在实际开发中,我们经常需要从服务器端下载文件,而传统
本文将介绍如何通过AJAX下载Excel文件流。通过AJAX,我们可以在不刷新整个页面的情况下,向服务器发送请求并获取响应数据。在某些场景下,我们需要通过AJAX下载Excel文件流,以便于在前端使用或保存到本地。本文将详
Ajax是一种用于客户端和服务器之间的异步通信技术。通过Ajax,我们可以在不刷新整个页面的情况下向服务器发送请求并获得响应数据。而在Ajax的基础上,.get和.post是两种常用的请求方法,它们分别用于发送GET和POST请
AJAX(Asynchronous JavaScript and XML)是一种在网页上实现异步数据传输的技术。通过AJAX,网页可以在不刷新整个页面的情况下与服务器进行数据交互,提升用户体验和页面性能。在实际应用中,AJAX广泛用于表单提交、
在使用Ajax下拉加载数据的过程中,有时候会出现无法取到360度的问题。这个问题可能是由于代码逻辑的问题导致的,也有可能是网络延迟引起的。为了解决这个问题,我们需要对代码进行仔细排查,并且在合适的地方添加适当
本文将介绍Ajax和.post之间的区别。Ajax是一种用于在网页上进行异步通信的技术,能够在不刷新整个页面的情况下更新部分页面内容。.post是jQuery中的一个方法,用于向服务器发送POST请求。虽然它们都可以用于发送异步
AJAX(Asynchronous JavaScript and XML)是一种在Web页面上进行异步数据请求和交互的技术。它的出现使得页面在后台与服务器进行数据交互的同时,不需要重新加载整个页面。在网页开发中,常常需要实现文件上传功能,