Ajax学习笔记


ajax 的全称是Asynchronous JavaScript and XML(异步的JavaScript和XML),即用JavaScript去异步的获取XML文件作为交换格式,由 Jesse James Garrett 在2005年提出。其中,Asynchronous 是异步的意思,它有别于传统web开发中采用的同步的方式。

关于同步和异步
首先常用的是:普通B/S模式代表同步,AJAX技术代表异步
同步:提交请求->等待服务器处理->处理完毕返回 这个期间客户端浏览器不能干任何事
异步: 请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕
(参考:同步与异步的概念
Ajax是一种无需刷新页面就能够从服务器获取数据的技术,会带来更好的用户体验。

Ajax并非一种新的技术,而是几种原有技术的结合体。它由下列技术组合而成。

  1. 使用CSS和HTML来实现页面,表达信息。
  2. 使用XMLHttpRequest来和web服务器进行数据的异步交换。
  3. 使用javascript来操作DOM,实现动态局部刷新。

ajax原理和XmlHttpRequest对象

Ajax的原理简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面。这其中最关键的一步就是从服务器获得请求数据。
Ajax工作原理

Ajax技术的核心是XHR(XMLHttpRequest对象)
XMLHttpRequest是在IE5中首先引入的,是一种支持异步请求的技术。简单的说,也就是javascript可以及时向服务器提出请求和处理响应,而不阻塞用户。达到无刷新的效果。
XHR为向服务器发送请求和解析服务器响应提供了流畅的接口,能够以异步方式从服务器取得更多信息,当用户单击后,可以不必刷新页面也能取得新数据。可以使用XHR对象取得新数据,然后再通过DOM将新数据插入到页面中。

Ajax通信与数据格式无关,这种技术就是无需刷新页面即可从服务器取得数据,但不一定是XML数据。

XmlHttpRequest对象

使用Ajax技术,首先要创建xhr对象。

1
2
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
//所有现代浏览器均支持 XMLHttpRequest 对象(IE5 和 IE6 使用 ActiveXObject)

XMLHttpRequest这个对象的属性有:

属性 描述
onreadystatechange 每次状态改变所触发事件的事件处理程序。
responseText 从服务器进程返回数据的字符串形式。
responseXML 从服务器进程返回的DOM兼容的文档数据对象。
status HTTP响应状态,从服务器返回的数字代码,比如常见的404(未找到)和200(已就绪)
status Text 伴随状态码的字符串信息
readyState 对象状态值

readyState对象状态值:

readyState 含义
0 (未初始化) 对象已建立,但是尚未初始化(尚未调用open方法)
1 (初始化) 对象已建立,尚未调用send方法
2 (发送数据) send方法已调用,但是当前的状态及http头未知
3 (数据传送中) 已接收部分数据,因为响应及http头不全,这时通过responseBody和responseText获取部分数据会出现错误
4 (完成) 数据接收完毕,此时可以通过通过responseXml和responseText获取完整的回应数据

ajax通信

Status:HTTP响应状态码,常见的有:
HTTP响应状态码

使用XMLHttpRequest对象向服务器发送请求

XMLHttpRequest这个对象向服务器发送请求的方法有:open()和send().

  1. open方法:开启一个请求以备发送,但它不会向服务器端发起正式请求。
    xhr.open(method,url[,async = true]);
    open方法指定了:

    • 向服务器发送请求的方式,即post还是get。
    • 请求的url地址和传递的参数。
    • 传输方式,false为同步,true为异步。默认为true,一般省略不填写。如果是异步通信方式(true),客户机就不等待服务器的响应;如果是同步方式(false),客户机就要等到服务器返回消息后才去执行其他操作。我们需要根据实际需要来指定同步方式,在某些页面中,可能会发出多个请求,甚至是有组织有计划有队形大规模的高强度的request,而后一个是会覆盖前一个的,这个时候当然要指定同步方式。
  2. Send方法用来发送请求。
    xhr.send([data = null]);
    如果使用POST请求,send()里需要有内容。

  3. 向服务器发送GET请求:用于向服务器查询某些信息。

    1
    2
    xhr.open("get","example.php?name1=value1&name2=value2",true);
    xhr.send(null);
  4. 向服务器发送POST请求:用于向服务器发送需要保存的数据

    1
    2
    3
    4
    5
    xhr.open('post','example.php',true);
    //使用setRequestHeader()来添加HTTP头
    xhr.setRequestHeader('content-type','application/x-www-form-urlencoded');
    //在send()方法中添加需要发送的数据。
    xhr.send('name1=value1&name2=value2');
  5. 请求参数序列化
    对于get请求,查询字符串中每个参数的名称和值必须使用encodeURIComponent()进行编码,然后才能放到URL的末尾,所有的名值对必须用&分割;
    对于post请求,发送的数据也必须使用encodeURIComponent()进行编码。
    因此,需要对这些参数/数据进行序列化。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    //参数序列化
    function serialize(data){
        if(!data) return '';
        var pairs = [];
        for(var name in data){
            if(!data.hasOwnProperty(name)) continue;
            if(typeof data[name] === 'function'continue;
            var value = data[name].toString();
            name = encodeURIComponent(name);
            value = encodeURIComponent(value);
            pairs.push(name + '=' + value);
        }
        return pairs.join('&');
    }
    //GET请求
    var ulr = 'example.json?' + serialize(formdata);
    xhr.open('get',url,true);
    xhr.send(null);
    //post请求
    xhr.open('post','example.json',true);
    xhr.setRequestHeader('content-type','application/x-www-form-urlencoded');
    xhr.send(serialize(formdata));
使用XMLHttpRequest对象向取得响应:
  • responseText:获得字符串形式的响应数据
  • responseXML:获得XML形式的响应数据
  • status和statusText:以数字和文本形式返回HTTP状态码
  • getAllResponseHeader():获取所有的响应报头
  • getResponseHeader():查询响应中的某个字段的值
  • readyState:表示请求/响应过程的当前活动阶段,其属性值包含0-4变化(参考上文)
  • readystatechange:只要readyState属性的值由一个值变成另一个值,都会触发一次readystatechange事件。可以利用此事件来检测每次状态变化后readyState的值。

一个完整的AJAX案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//创建xhr对象。所有现代浏览器均支持 XMLHttpRequest 对象(IE5 和 IE6 使用 ActiveXObject)
    var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
    //处理返回数据。当请求被发送到服务器时,我们需要执行一些基于响应的任务。每当 readyState 改变时,就会触发 onreadystatechange 事件。
    xhr.onreadystatechange = function ({
        if (xhr.readyState == 4) {
            //http 状态码 200到300是指服务端正常返回;304是告诉客户端取缓存数据
            if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
                callback(xhr.responseText);
            } else {
                alert("请求错误:" + xhr.status + " " + xhr.statusText);
            }
        }
    };
//发送请求
    xhr.open('post', url, true);
    xhr.setRequestHeader('Content-Type''application/x-www-form-urlencoded');
    xhr.send(null);

XMLHttpRequest是完全用来向服务器发出一个请求的,它的作用也局限于此,但它的作用是整个ajax实现的关键,因为ajax无非是两个过程,发出请求和响应请求。并且它完全是一种客户端的技术。而XMLHttpRequest正是处理了服务器端和客户端通信的问题所以才会如此的重要。

Ajax封装函数

以下代码是将上述的过程进行的封装,使得使用时只要调用函数并在回调函数中实现功能就可以了

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
 <script>
/*
* method是请求方式
* url是网络请求的地址
* postboidy是post方式请求时的提交数据
* successCallback是请求成功的函数
* errorCallback是请求失败的函数
*/


function request (method,url,postbody,successCallback,errorCallback) {
//创建一个请求对象
if(window.XMLHttpRequest){
var request = new XMLHttpRequest();
}else{
var request = new ActiveXObject("Microsoft.XMLHttp");
}

if(arguments[0]=="POST"){
//创建请求
request.open(method,url,true);
//设置上传类型
request.setRequestHeader("content-type","application/x-www-form-urlencoded");
}else if(arguments[0]=="GET"){
request.open(method,url,true);
}
//发送请求
request.send(postbody);
//状态监听
request.onreadystatechange = function () {
if(request.readyState ==4 && request.status == 200){
//请求成功的回调函数
if(successCallback){
successCallback(request.responseText);
}
} else if (request.readyState == 4 && request.status != 200) {
//请求失败的回调函数
if(errorCallback){
errorCallback(request.statusText);
}
}
}
}
</script>

使用方法举例:
下面定义了一个简单的表单提交用户名和密码,使用回调函数拿到后台返回的JSON串后,转换成对象再取出其中的信息,告知用户是登陆成功还是失败

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
45
46
47
48
49
//html部分
//调用封装好的函数
<script src="request.js"></script>
<div class="form">
<input type="text" id="username">
<input type="password" id="passwd">
<button id="loginBtn">登录</button>
</div>

//js部分
<script>
var username = document.getElementById("username");
var passwd = document.getElementById("passwd");
var loginBtn = document.getElementById("loginBtn")
loginBtn.onclick = function () {
//设置请求地址及提交内容
var url = "login.php";
var postbody = "username="+username.value+"&passwd="+passwd.value;
//发起ajax请求,并使用回调函数实现功能
request("POST",url,postbody,function (resText) {
//把json格式的字符串转换成对象
var obj = JSON.parse(resText);
alert(obj.msg);
});
}
</script>


//php部分login.php
<?php
//从请求中获取用户名和密码
$username = $_POST["username"];
$passwd = $_POST["passwd"];
//连接服务器
@$mysqli = new mysqli("localhost","root","","user");
$mysqli->query("set names utf8");
//查询语句
$sql = "SELECT * FROM user WHERE username='$username' AND passwd='$passwd'";
//数据库执行查询
$result = $mysqli->query($sql);
//判断查询结果是否有值,并定义返回字符串
//echo出来的就是返回前端的数据
if($result->num_rows > 0){
echo '{"errorcode":0,"msg":"登陆成功"}';
}else{
echo '{"errorcode":1,"msg":"用户名或密码错误"}';
}
//关闭服务器
$mysqli->close();
?>

参考链接:http://www.jianshu.com/p/ff9e1139ea51

XMLHttpRequest 2级

XMLHttpRequest 1级只是把已有的XHR对象的实现细节描述了出来。而XMLHttpRequest 2级则进一步发展了XHR。
2 级 XMLHttpRequest 引入了大量的新功能(例如跨源请求、上传进度事件以及对上传/下载二进制数据的支持等),一举封杀了我们网络应用中的疯狂黑客。这使得 AJAX 可以与很多尖端的 HTML5 API 结合使用,例如 File System API、Web Audio API 和 WebGL。

xhr.overrideMimeType()方法

overrideMimeType()用于重写XHR响应的MIME类型。返回响应的MIME类型决定了XHR对象如何处理它。
现在,让我们利用 XMLHttpRequest 新增的 responseType 和 response 属性,告知浏览器我们希望返回什么格式的数据。

xhr.responseType
在发送请求前,根据您的数据需要,将 xhr.responseType 设置为“text”、“arraybuffer”、“blob”或“document”。请注意,设置(或忽略)xhr.responseType = ‘’ 会默认将响应设为“text”。
xhr.response
成功发送请求后,xhr 的响应属性会包含 DOMString、ArrayBuffer、Blob 或 Document 形式(具体取决于 responseTyp 的设置)的请求数据。
凭借这个优秀的新属性,我们可以修改上一个示例:以 ArrayBuffer 而非字符串的形式抓取图片。将缓冲区移交给 BlobBuilder API 可创建 Blob:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder;

var xhr = new XMLHttpRequest();
xhr.open('GET', '/path/to/image.png', true);
xhr.responseType = 'arraybuffer';

xhr.onload = function(e) {
if (this.status == 200) {
var bb = new BlobBuilder();
bb.append(this.response); // Note: not xhr.responseText

var blob = bb.getBlob('image/png');
...
}
};

xhr.send();

ArrayBuffer 响应

ArrayBuffer 是二进制数据通用的固定长度容器。如果您需要原始数据的通用缓冲区,ArrayBuffer 就非常好用,但是它真正强大的功能是让您使用 JavaScript 类型数组创建底层数据的“视图”。实际上,可以通过单个 ArrayBuffer 来源创建多个视图。例如,您可以创建一个 8 位整数数组,与来自相同数据的现有 32 位整数数组共享同一个 ArrayBuffer。底层数据保持不变,我们只是创建其不同的表示方法。

例如,下面以 ArrayBuffer 的形式抓取我们相同的图片,但是现在,会通过该数据缓冲区创建无符号的 8 位整数数组。

1
2
3
4
5
6
7
8
9
10
11
var xhr = new XMLHttpRequest();
xhr.open('GET', '/path/to/image.png', true);
xhr.responseType = 'arraybuffer';

xhr.onload = function(e) {
var uInt8Array = new Uint8Array(this.response); // this.response == uInt8Array.buffer
// var byte3 = uInt8Array[4]; // byte at offset 4
...
};

xhr.send();

Blob 响应

如果您要直接处理 Blob 且/或不需要操作任何文件的字节,可使用 xhr.responseType=’blob’:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
window.URL = window.URL || window.webkitURL;  // Take care of vendor prefixes.

var xhr = new XMLHttpRequest();
xhr.open('GET', '/path/to/image.png', true);
xhr.responseType = 'blob';

xhr.onload = function(e) {
if (this.status == 200) {
var blob = this.response;

var img = document.createElement('img');
img.onload = function(e) {
window.URL.revokeObjectURL(img.src); // Clean up after yourself.
};
img.src = window.URL.createObjectURL(blob);
document.body.appendChild(img);
...
}
};

xhr.send();

Blob 可用于很多场合,包括保存到 indexedDB、写入 HTML5 文件系统 或创建 Blob 网址(如本例中所示)。

参考资源:XMLHttpRequest2 新技巧 http://www.html5rocks.com/zh/tutorials/file/xhr2/

HTTP请求

一个完整的HTTP请求过程,通常有下面7个步骤:

  1. 建立TCP连接
  2. Web浏览器向Web服务器发送请求命令
  3. Web浏览器发送请求头信息
  4. Web服务器应答
  5. Web服务器发送应答头信息
  6. Web服务器向浏览器发送信息
  7. Web服务器关闭TCP连接

一个HTTP请求一般由4部分组成:

  1. HTTP请求的方法或动作,比如GET/POST请求
    • GET:向服务器请求信息,一般用于信息获取,使用URL传递参数,对所发送信息的数量有限制,一般在2000个字符以内
    • POST:向服务器发送信息,一般用于修改服务器上的资源。对所发送信息的数量无限制
  2. 正在请求的URL
  3. 请求头,包含一些客户端环境信息、身份验证信息等
  4. 请求体(请求正文),包含客户提交的查询字符串信息,表单信息等。

一个HTTP响应一般由3部分组成:

  1. 一个数字和文字组成的状态码,用来显示请求是成功还是失败
  2. 响应头,和请求头一样,包含许多有用的信息,例如服务器类型、日期时间、内容类型和长度等。
  3. 响应体:也就是响应正文。

HTTP状态码:
HTTP状态码由3位数字构成,其中首位数字定义了状态码的类型:

  • 1XX:信息类,表示收到Web浏览器请求,正在进一步处理中。
  • 2XX:成功,表示用户请求被正确接收、理解和处理,比如 200 OK。
  • 3XX:重定向,表示请求没有成功,客户必须采取进一步的动作
  • 4XX:客户端错误,表示客户端提交的请求有错误,例如404 Not Found,意味着请求中所引用的文档不存在。
  • 5XX:服务器错误,表示服务器不能完成对请求的处理,如500错误。

Ajax原理解读:
把服务器端看成一个数据接口,它返回的是一个纯文本流,当然,这个文本流可以是XML格式,可以是Html,可以是Javascript代码,也可以只是一个字符串。这时候,XMLHttpRequest向服务器端请求这个页面,服务器端将文本的结果写入页面,这和普通的web开发流程是一样的,不同的是,客户端在异步获取这个结果后,不是直接显示在页面,而是先由javascript来处理,然后再显示在页面。

Ajax优缺点

Ajax的优点

  1. 页面无刷新,在页面内与服务器通信,给用户的体验非常好。
  2. 使用异步方式与服务器通信,不需要打断用户的操作,具有更加迅速的响应能力。
  3. 可以把以前一些服务器负担的工作转嫁到客户端,利用客户端闲置的能力来处理,减轻服务器和带宽的负担,节约空间和宽带租用成本。并且减轻服务器的负担,ajax的原则是“按需取数据”,可以最大程度的减少冗余请求,和响应对服务器造成的负担。
  4. 基于标准化的并被广泛支持的技术,不需要下载插件或者小程序。

Ajax的缺点

  1. ajax干掉了back按钮,即对浏览器后退机制的破坏。后退按钮是一个标准的web站点的重要功能,但是它没法和js进行很好的合作。这是ajax所带来的一个比较严重的问题,因为用户往往是希望能够通过后退来取消前一次操作的。
  2. 安全问题:ajax技术就如同对企业数据建立了一个直接通道。这使得开发者在不经意间会暴露比以前更多的数据和服务器逻辑。ajax的逻辑可以对客户端的安全扫描技术隐藏起来,允许黑客从远端服务器上建立新的攻击。还有ajax也难以避免一些已知的安全弱点,诸如跨站点脚步攻击、SQL注入攻击和基于credentials的安全漏洞等。
  3. 对搜索引擎的支持比较弱
  4. 破坏了程序的异常机制
  5. 其他方面的一些问题:如违背了url和资源定位的初衷。例如,我给你一个url地址,如果采用了ajax技术,也许你在该url地址下面看到的和我在这个url地址下看到的内容是不同的。这个和资源定位的初衷是相背离的。

AJAX跨域处理

同源策略

两个页面拥有相同的协议(Protocol)、端口(Port)、和主机(host)那么这两个页面就是属于同一个源(Origin)。
同源策略

跨域资源访问

  • 当协议、端口和主机中任意一个不相同时,都算作不同源(域)
    -不满足同源策略的资源访问,叫跨域资源访问
    比如:http://www.xifengxx.comhttp://www.baidu.com 这两者之间相互请求资源,是跨域资源访问。
    -W3C 定义了 CORS。
    -现代浏览器已经实现了对 CORS 的支持。
    Javascript出于安全方面的考虑,不允许跨域调用其他页面的对象。
    www.abc.com/index.html调用www.abc.com/service.php (非跨域)
    www.abc.com/index.html调用www.efg.com/service.php (跨域)
    www.abc.com/index.html调用bbs.abc.com/service.php (跨域)
    www.abc.com/index.html调用www.abc.com:81/service.php(跨域)
    www.abc.com/index.html调用https://www.abc.com/service.php(跨域)

CORS标准原理(Cross-Origin Resource Sharing)

CORS标准原理

  1. 浏览器捕获到a.b.com应用往x.y.com的服务器发起的请求
  2. 浏览器检查请求情况确定是否需要先做一次预请求来验证x.y.com的服务器是否允许发当前请求过去,如果需要发预请求则浏览器发起一个OPTIONS的请求到x.y.com的服务器验证继续第3步,否则直接发送请求到x.y.com服务器继续第5步
  3. 服务器根据浏览器发过来的header信息,然后根据服务器端对资源的配置返回资源的实际控制权限配置
  4. 浏览器验证预请求返回的信息,判断是否可以将请求发送到x.y.com的服务器,如果不行则异常退出,否则继续第5步
  5. 浏览器发送实际请求至x.y.com服务器
  6. 服务器返回请求数据及资源控制配置信息至浏览器
  7. 浏览器验证资源控制信息是否允许当前实际请求的取到数据,如果不允许则异常退出,否则继续第8步
  8. 浏览器返回x.y.com返回的数据至a.b.com的应用

CORS(跨源资源共享)定义了在必须访问跨源资源时,浏览器与服务器应该如何沟通。CORS背后的基本思想,就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。
如何实现?
在服务器端做一些小小的改造,添加如下代码:
header(‘Access-Control-Allow-Origin:*’);
header(‘Access-Control-Allow-Methods:POST,GET’);

其他跨域技术

  • Frame 代理
    -JSONP
    -Comet
    -Web Sockets
Frame代理

此模式主要参照CORS规范原理,通过在目标服务器放置一个代理文件,然后通过该代理文件来与服务器端进行数据交互,返回数据通过消息通讯返回给上层应用来实现跨域的数据交互。
此方式也支持通过代理文件配置资源可访问的来源。
Frame代理

  1. 当a.b.com的应用要往x.y.com的服务器取数据时,首先会用iframe载入预先放置在x.y.com服务器上的代理文件
  2. 服务器端返回做了配置的代理文件
  3. 代理文件载入完成后a.b.com的应用将要发送的请求指令通过消息通信方式传递给代理文件
  4. 代理文件验证a.b.com是否在预先配置的白名单中,如果不在则异常返回,否则直接发送请求至x.y.com服务器
  5. 服务器返回数据至代理文件
  6. 代理文件通过消息通讯机制将请求结果返回给a.b.com的应用

优点:
-参照 CORS 标准
-支持各种请求方法 GET POST PUT DELETE
缺点:
-需要在目标服务器放置代理文件
-由于首次发起请求时需要载入代理文件,在载入代理文件之前的所有请求都会存在一定的延时。
-对于低版本浏览器受限于消息通讯机制的限制,对于并发量大的请求返回时可能存在较大延时。

JSONP

JSON with Padding(填充式 JSON): 用于解决主流浏览器的跨域数据访问的问题。
利用<script> 可以跨域,请求一段 JavaScript 代码,然后执行 JavaScript 代码来实现跨域。
JSONP支持get请求方式,不支持post请求方式。
JSONP
举例:
在www.aaa.com页面中:

1
2
3
4
5
6
<script>
function jsonp(json){
alert(json["name"]);
}
</script>
<script src="http://www.bbb.com/jsonp.js"></script>

在www.bbb.com页面中:
jsonp({'name':'洪七','age':24});

DEMO示例

来源:慕课网-Ajax全接触

分析:
通过Ajax实现动态无刷新页面进行查询/添加操作。

涉及技术点:

  1. HTML+CSS简单布局
  2. Ajax + JSON 实现页面查询/添加操作。
  3. jQuery基础运用
  4. Ajax跨域解决方案(JSONP + CORS)

DEMO下载:下载地址

参考资源:

  1. NEJ的前后端通讯系统:
    https://github.com/genify/nej/blob/master/doc/AJAX.md (☆☆☆☆)
  2. JavaScript跨域与解决方法:
    http://www.cnblogs.com/rainman/archive/2011/02/20/1959325.html(☆☆写的不错,但看不懂)
  3. 跨域基本知识:
    http://www.cnblogs.com/scottckt/archive/2011/11/12/2246531.html(☆☆☆☆)
  4. JavaScript函数节流:
    http://www.alloyteam.com/2012/11/javascript-throttle/(☆☆☆☆)
  5. Ajax基础知识讲解:
    http://www.nowamagic.net/librarys/veda/detail/750 (☆☆☆☆)
  6. Ajax使用学习:http://www.jianshu.com/p/ff9e1139ea51 (☆☆☆☆☆)
坚持原创技术分享,您的支持将鼓励我继续创作!