XMLHttpRequest 学习

XHR介绍

XMLHttpRequest 对象用于在后台与服务器交换数据。

可以在chrome console输入以下代码

1
2
3
4
var url = 'https://abigaleypc.github.io/';
var xmlhttp=new XMLHttpRequest(); //创建 XMLHttpRequest 对象
xmlhttp.open("GET",url,true); //open() 方法已调用,但是 send() 方法未调用。请求还没有被发送。
xmlhttp.send(null); //Send() 方法已调用,HTTP 请求已发送到 Web 服务器。未接收到响应。

访问xmlhttp可以看到以下结果:

1
2
3
4
5
6
7
8
9
10
XMLHttpRequest:{
onabort : null,
onerror : null,
readyState : 4,
response : '……',
responseText : '……',
status : 200,
statusText :'OK'
……
}

属性

  • readyState

    HTTP 请求的状态.当一个 XMLHttpRequest 初次创建时,这个属性的值从 0 开始,直到接收到完整的 HTTP 响应,这个值增加到 4。
    5 个状态中每一个都有一个相关联的非正式的名称,下表列出了状态、名称和含义:

状态 名称 描述
0 Uninitialized 初始化状态。XMLHttpRequest 对象已创建或已被 abort() 方法重置。
1 Open open() 方法已调用,但是 send() 方法未调用。请求还没有被发送。
2 Sent Send() 方法已调用,HTTP 请求已发送到 Web 服务器。未接收到响应。
3 Receiving 所有响应头部都已经接收到。响应体开始接收但未完成。
4 Loaded HTTP 响应已经完全接收。

readyState 的值不会递减,除非当一个请求在处理过程中的时候调用了 abort() 或 open() 方法。每次这个属性的值增加的时候,都会触发 onreadystatechange 事件句柄。

  • responseText

    目前为止为服务器接收到的响应体(不包括头部),或者如果还没有接收到数据的话,就是空字符串。
    如果 readyState 小于 3,这个属性就是一个空字符串。当 readyState 为 3,这个属性返回目前已经接收的响应部分。如果 readyState 为 4,这个属性保存了完整的响应体。
    如果响应包含了为响应体指定字符编码的头部,就使用该编码。否则,假定使用 Unicode UTF-8。

  • responseXML

    对请求的响应,解析为 XML 并作为 Document 对象返回。

  • status

    由服务器返回的 HTTP 状态代码,这类状态代码表明服务器成功地接受了客户端请求。

    • 200 - OK 一切正常,对GET和POST请求的应答文档跟在后面。
    • 201 - Created 服务器已经创建了文档,Location头给出了它的URL。
    • 202 - Accepted 已经接受请求,但处理尚未完成。
    • 203 - Non-Authoritative Information 文档已经正常地返回,但一些应答头可能不正确,因为使用的是文档的拷贝,非权威性信息(HTTP 1.1新)。
    • 204 - No Content 没有新文档,浏览器应该继续显示原来的文档。如果用户定期地刷新页面,而Servlet可以确定用户文档足够新,这个状态代码是很有用的。
    • 205 - Reset Content 没有新的内容,但浏览器应该重置它所显示的内容。用来强制浏览器清除表单输入内容(HTTP 1.1新)。
    • 206 - Partial Content 客户发送了一个带有Range头的GET请求,服务器完成了它(HTTP 1.1新)。
    • 详细参考:XMLHTTPRequest状态status完整列表
  • statusText

    这个属性用名称而不是数字指定了请求的 HTTP 的状态代码。也就是说,当状态为 200 的时候它是 “OK”,当状态为 404 的时候它是 “Not Found”。和 status 属性一样,当 readyState 小于 3 的时候读取这一属性会导致一个异常。

Angular-resource

angular附带了两种请求办法:$http 和 $rescource

安装

ngResource模块是一个可选的angularjs模块,如果需要使用,我们要单独引用js

1
<script type="text/javascript" src="/javascripts/angular-resource.js">

应用$resource

我们并不是直接通过$resource服务本身同服务器通信,$resource是一个创建资源对象的工厂,用来创建同服务端交互的对象。

1
var User = $resource('/api/users/:userId', {userId:'@id'});

返回的User对象包含了同后端服务进行交互的方法,我们可以把User对象理解成同RESTFul的后端服务进行交互的接口。
该对象包含两个get类型的方法已经三个非get类型的方法。

用法 解释
User.get({id:’123’}, successFn, errorFn) 该方法向url发送一个get请求,并期望一个json类型的响应。这里会向/api/users/123发送一个请求,successFn处理请求成功响应,errorFn处理错误。
User.query(params, successFn, errorFn) 同get()方法使用类似,一般用来请求多条数据。
save(params, payload, successFn, errorFn) save方法会发起一个post请求,params参数用来填充url中变量,对象payload会作为请求体进行发送
delete(params, payload, successFn,errorFn) delete方法一个DELETE请求,payload作为消息体进行发送
remove(params, payload, successFn, errorFn) 同delete类似,不同的是remove用来移除多条数据

通过$resource生成的对象来同服务器进行交互的时候,我们看可以定义处理成功以及处理失败的函数,这些函数接受的参数不仅仅是简单的对象,而是经过包装之后的对象,会被添加$save(), $remove(), $delete三个方法,可以直接调用这三个方法来后服务端进行交互。

1
2
3
4
User.get({id:'123'}, function(user){
user.name = 'changeAnotherName';
user.$save(); //这里等价于User.save({id:'123'},{name:'changeAnotherName'})
});

扩展$resource

$resource对常见的五种请求进行封装,我们还可以对$resource进行扩展。
这里要扩展$resource我们需要传入第三个参数,该参数是一个对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$resource('/api/users',{},{
sendEmail:{
method:'',
url:'',
params:{},
isArray:boolean,
transformRequest:函数或者函数数组
transformResponse:函数或者函数数组
cache:布尔型或缓存对象
timeout:数值或promise对象
withCredentials:布尔类型
responseType:字符串,用来设置XMLHttpRequestResponseType属性
}
})

我们也可以将$resource服务当做自定义服务的基础。

1
2
3
angular.module('testApp', ['ngResource']),factory('UserService',['$resource', function($resource){
return $resource(url,{},{});
}]);

这种方法很常用,例如

Server中:

1
2
3
4
5
6
7
8
9
10
11
export default angular
.module('app.services', [])
.factory('libraryService', libraryService);
libraryService.$inject = ['$resource']
function libraryService($resource) {
getLibraryTags: function() {
return $resource('/apis/auth/tags').query();
}
}

Controller中:(需要注意的是:该controller引入以上server时需要是同个module或者引入该module)

1
libraryService.getLibraryTags()

如果想用.then().then()链式写法,可改下Serives添加promise:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export default angular
.module('app.services', [])
.factory('libraryService', libraryService);
libraryService.$inject = ['$resource']
function libraryService($resource) {
return {
getBookInfo: function(currentPage, itemsPerPage, sortBy) {
return $resource('/apis/auth/new').save({
currentPage: currentPage,
itemsPerPage: itemsPerPage,
sortBy: sortBy
}).$promise; // 添加promise
}
}
}

Controller中:

1
2
3
libraryService.getNewBookList(vm.currentPage, vm.itemsPerPage, vm.sortBy).then(function(data) { //使用then()
vm.bookList = data;
});