AngularJS 学习笔记-第二章:与后端服务器通信
AngularJS能够通过XMLHttpRequest(XHR)和JSONP请求与各种后端交流,拥有通用的$http服务以进行XHR和JSONP调用,以及专门面向Restful后端接口的$resource服务
在本章中,将研究与后端通信的API与技术,特别是一下内容:
- 使用$http服务进行基本的XHR调用,已经进行相应的测试
- 利用$q服务提供的promise API进行有效的异步请求
- 使用$resource工厂轻松与RESTful后端进行沟通
- 根据后端需求构建自定义的与$resource类似的API
$http API快速导览
GET | $http.get(url, config) |
POST | $http.post(url, data, config) |
PUT | $http.put(url, data, config) |
DELETE | $http.delete(url, config) |
HEAD | $http.head |
- url: 调用目标URL
- data:请求体中送出的数据
- config:包含额外配置信息,对请求和响应都有影响
处理HTTP响应:请求可能成功或者失败,AngularJS提供两种方法以注册对应这两种结果的回调:success (200~299范围调用success,其余的状态吗则进入error)和error。
我们可以在调用$http方法返回的对象上,注册成功与失败的回调(callback)
- data:实际的响应数据
- status:响应的HTTP状态
- headers:访问HTTP响应头信息的函数
- config:请求触发时提供的配置对象
配置对象说明
- method:所用的HTTP方法
- url: 请求的目标URL
- params: URL参数
- headers: 额外的请求头
- timeout:XHR请求终止前的超时时间(毫秒)
- cache:XHR GET请求的缓存开关
- transformRequest\transferResponse:在于后端交换数据前或交换后,对数据进行处理的数据变换函数
var base_url = 'http://localhost:8080/' angular.module('myapp1', []) .controller('myController', function($scope, $http) { var query = $http.get(base_url + "get"); query.success(function(data, status, headers, config) { console.log(data); $scope.response = data; }); query.error(function(data, status, headers, config){ console.log('fail'); console.log(data); }); var cars = { toyota: { from: 'japan', price: 100000 }, benz: { from: 'Germany', price: 500000 } } //post和put的data接受任何Javascript对象(或者字符串),如果是对象则默认被转化为JSON字符串 var post = $http.post(base_url + '/post/car', cars); //$http服务会视图对任何看起来像JSON的响应(以{},[])都执行从JSON字符串到Javascript对象的转化 post.success(function(data, status, headers, config) { console.log(data); }); });
为了测试简单的restful,你可以用sts创建一个简单点 springboot项目,随便写几个get,post的API如下:
public class HelloController { @RequestMapping("/hello/{name}") public String hello(@PathVariable("name") String name, Model model) { model.addAttribute("name", name); return "hello"; } @RequestMapping("/get") public @ResponseBody String hello(HttpServletResponse response) { //为了解决cross domain的问题,你不需要allow *,你的index.html并不是部署在和springboot所在的localhost:8080的服务器上 response.addHeader("Access-Control-Allow-Origin", "*"); return "{\"firstName\": \"John\", \"lastName\": \"Smith\", \"age\": 25}"; } @RequestMapping(value="/post/car", method=RequestMethod.POST) public void post1(@RequestBody String body, HttpServletResponse response){ System.out.println(body); response.addHeader("Access-Control-Allow-Origin", "*"); } }
Promise API
promise API的主要思想是,为异步世界带来我们在同步编程世界中所享有的那些便利之处,比如链式方法调用和错误处理。
在Promise API中,通常有两个角色:一个是控制未来任务的执行(延迟调用)占位符(promise),领一个则是依赖于未来任务的执行结果(保证承诺结果,resovle、reject)
AngularJS拥有非常轻量化的Promise API实现–$q服务,位数不少的AngularJS服务(主要是$http, $timeout等)相当依赖promise API风格,所以为了有效运行这些服务,需要熟悉$q.
//此处省略$q的介绍,楼主暂时没看懂,而且觉得用处不太大,以后学了再补上。
Promise API与http的关系,http返回的承诺对象为then,这让我们能以如下方式覆盖回调注册
var query = $http.get(base_url + "get"); query.then(function(data, status, headers, config) { console.log(data); $scope.response = data; }, function(data, status, headers, config) { console.log('fail'); console.log(data); } )
RESTful端点场提供CRUD操作,虽然这样的端点交互的代码通常很简单直接,不过写起来却很单调乏味。$resource服务允许我们消除重复代码,并让我们在更高的抽象级别上操作,用resources的形式去思考数据操纵,用方法调用来代替低级别的HTTTP调用。
$resource服务被分发在单独的文件中(angular-resource.js),属于专用模块(ngResource)。为了利用$resource服务,我们需要包含angular-resource.js文件,并在应用模块中声明对ngResource的模块依赖。
//HTML <div ng-controller="myController"> <ul > <li ng-repeat='user in users'>Name : {{user.name}}</li> </ul> </div> //JS var base_url = 'http://localhost:8080/' angular.module('myapp1', ['ngResource']) .factory('Users', function($resource) { return $resource(base_url + 'get'); }) .controller('myController', function($scope, Users) { $scope.users = Users.query(); })
resourceAPI通过
resource()方法来使用$resources服务。这个方法可以接受三个参数。
- url(必选)
我们在这里传入一个包含所有参数的,用来定位资源的参数化URL字符串模板(参数以“:”为前缀)
//这里需要注意的是如果:之前的参数是空的(:id),那么URL中的这部分会被压缩成一个.符号。 //如果我们使用的服务器要求在URL中输入端口号,例如:http://localhost:8080/:id 则必须对:转义 //http://localhost\:8080/:id $resource('/api/users/:id.:format',{ format:'json', id: '123' });
- paramDefaults(可选)
第二个参数包含了发送请求时URL重参数的默认值。对象中的键会与参数名进行匹配。如果我们传入了一个没有在URL中设置过的参数,那它会以普通的查询字符串的形式被发送。
例如,如果URL字符串具有/api/users/:id这样的签名,并且我们将默认值设置为{id:’123’, name:’Ari’},那么URL最终被转化成/api/users/123?name=Ari 这里可以像上面一样硬编码一个值,也可以设置它从一个数据对象中读取动态值。 如果要设置动态之,需要在值之前加上@字符作为前缀 {id:’@_id.$oid’}
- actions(可选)
动作对象是具有自定义动作,并且可以对默认的资源动作进行扩展的hash对象。
对象的键就是自定义动作的名字,而$http设置的对象的值会对URL中相应的参数进行替换。
$resource('/api/users/:id.:format', { format: 'json', id: '123' }, { update: { methos: 'PUT' } }); //action: {method:?, params:?, isArray:?, headers:?} //isArray表示response是返回[]还是{}
$resource创建异步方法
$scope.users = Users.query(); console.log($scope.users.length); //这里不会获得你期望的数组长度,而会返回0 //因此你必须使用异步方法去做。 Users.query(function(users){ $scope.users = users; console.log(users.length); })
$resource服务自动生成两套方法。其中一套方法会在类级别,另一套方法会在实例级别
类级别
- Users.query(params, successcb, errorcb) : GET请求期望JSON数据返回,用于取得条目列表 - Users.get(params, successcb, errorcb): GET请求,期望JSON返回单个对象,用于取得单个条目 - Users.save(params,payloadData, successcb, errorcb): POST请求,请载荷中产生 - Users.delete(params, successcb, errrorcb):DELETE请求。
params孕育我们为每个动作制定参数,它们将成为URL的一部分,或者作为查询字符串中的参数。
实例级别
var user = new Users({ name : 'SuperHero' }); user.$save(); user.$delete();
自定义方法
$resource工厂默认生成的方法对典型用例来说已经相当够用,但如果后端某些操作使用不同的HTTP动词(如PUT或者PATCH),那么在资源级别上添加自定义方法也相当容易。