和传统的 web 应用相比,mobile 有两大区别:
传统的 session/cookie 不再有效;
不返回 html,而是 Json 等数据
新的流程
用户使用用户名、密码登录;
服务端查询数据库,验证用户名和密码是否正确。如果正确,则根据用户信息创建 token,返回给客户端。客户端存储在本地 local storage
客户端每次请求,都带上这个 token.
服务端验证此 token 是否有效,如果有效,则返回 Json 数据.
——可以看到,这种 token-based 流程,可以应用于任何客户端,包括传统的 web 和流行的 mobile 客户端。
这种架构的优点:
参考:http://code.tutsplus.com/tutorials/token-based-authentication-with-angularjs-nodejs--cms-22543
文章的示例代码:https://github.com/huseyinbabal/token-based-auth-backend
客户端无关性. 通过 request headers传输,而不是 session/cookie,意味着它是无状态的. 可以从任何类型的客户端发送请求.
充分利用 CDN. 在传统 web 应用中,页面由服务端渲染,前端依赖于后端,这种依赖性其实是没有必要的。这种依赖带来了几个问题:
如果你要使用另外一个设计,html/css/js 等都要服务端全新配合。而使用 API 分离模式,前端的资源 html/css/js 等,都可以使用 CDN 缓存并 gzip 压缩。用户访问页面的时候,静态资源全部由 CDN 提供,API 则由服务端提供。
不存在 CSRF攻击. CSRF 是 web 安全的主要问题,无法确定这个请求是否可以信任。为了解决这个问题,每次请求都要带上 token pool,而在 token-based 验证中,toke 放在 authorization header 中,这是 CSRF 无法利用的。
持久化存储。传统的 session 在分布式存储方面有各种困难,需要用各种方式解决。而 token 设计,天然解决了这种问题,因为 token 本身就是持久化存储,每个分布式 API 服务端,都要验证的。
使用 $ngResource
可以直接将客户端模型和服务端模型映射起来,使用 RESTfull 接口形式。
官网文档:https://docs.angularjs.org/api/ngResource/service/$resource
1、准备 API
GET /api/post - Lists all posts
POST /api/post - Creates a new Post
GET /api/post/:id - Returns the data for that specific post with the id of :id
PUT /api/post/:id - Updates the information for a specific post
DELETE /api/post/:id - Deletes the specific post
2、定义映射关系
(当然需要先引入 angular-resource.js )
<script src="lib/ionic/js/ionic.bundle.js"></script>
<script src="lib/ionic/js/angular/angular-resource.min.js"></script>
然后修改 app.js,
(1)模块引入ngResource
angular.module('ionicApp', ['ngResource'])
(2)增加factory
.factory('Post', function($resource) {
return $resource('/api/post/:id’, {id:'@Id'}); // 必须定义齐全,也就是包括:id 部分,方便delete/update
// {id:’@Id’}的用处:将id映射到对象属性名Id
});
3、使用资源
创建对象的工厂之后,自带的action包括:
{
'get': {method:'GET'},
'save': {method:'POST'},
'query': {method:'GET', isArray:true},
'remove': {method:'DELETE'},
'delete': {method:'DELETE'}
};
其中 delete 和 remove 相同。区别:其实是同义词。只是因为 IE 中不能使用 delete(保留关键词),所以增加了一个同义词 remove。
1)查询所有 query
Post.query();
2)查询单个 get
var User = $resource('/user/:userId', {userId:'@id'});
var user = User.get({userId:123}, function() {
user.abc = true;
user.$save();
});
3、其他三个是实例方法 save/remove/delete,都要加上 $前缀使用
post.$save();
post.$remove();
4、也可以使用静态方法
Post.save(data);
Post.delete({ id: myId });
注意:删除时候的 {id:myId} 中的 id,必须和 factory 中 $resource('/api/post/:id') 的定义相同。如果是 :xid,则传递的时候也要改成 xid
5、如果使用实例方法,则 factory 增加定义
$resource('/api/post/:id', {id:'@Id'})
其中红色部分,是对象的主键属性。只有进行了映射,才能使用实例方法删除:
post.$remove()
6、如果要使用返回的结果,可以使用 then(fn) 方法
post.$save().then(function(retJson){
console.log(retJson);
});
4、列表视图
<ion-list
show-delete="shouldShowDelete"
show-reorder="shouldShowReorder"
can-swipe="listCanSwipe">
<ion-item ng-repeat="x in posts" class="item-thumbnail-left">
<img src=“*******">
<h2>{{x.Title}}</h2>
<p>{{x.Content}}</p>
<ion-option-button class="button-assertive" ng-click="deleteItem(x, $index)">
<i class="ion-close"></i> 删除
</ion-option-button>
<ion-reorder-button class="ion-navicon" on-reorder="moveItem(x, $fromIndex, $toIndex)">
</ion-reorder-button>
</ion-item>
</ion-list>
5、表单弹窗代码
下面是模态弹窗的视图,表单有两种方式:
其一:
<body ng-app="ionicApp" ng-controller="MainCtrl">
<ion-content padding="true">
<form ng-submit="newPost()">
<label>New Post:</label>
<textarea ng-model="postData.text"></textarea>
<button type="submit" class="button button-positive button-block">Create</button>
</form>
</ion-content>
</body>
代码部分:
1)先声明模型对象 $scope.postData = {};
2)然后绑定到表单 <textarea ng-model="postData.text"></textarea>
3)一旦用户修改模型,则自动同步到代码中
4)通过 $scope.postData 即可获取
其二:
<form ng-submit="createPost(x)">
<div class="list">
<label class="item item-input">
<input type="text" placeholder="标题" ng-model=“x.Title">
</label>
<label class="item item-input">
<input type="text" placeholder="内容" ng-model="x.Content">
</label>
使用代码(通过参数传递表单的值):
$scope.createPost = function(x) {
var post = new Post(x);
post.$save();
6、controller 代码
angular.module('ionicApp', ['ionic', 'ngResource'])
.factory('Post', function($resource) {
return $resource('http://10.211.55.6/xq/post/:id.aspx', {id:'@Id'});
})
.controller('MainCtrl', function($scope, Post) {
// 查询所有数据
$scope.posts = Post.query();
// 使用 ng-model 获取表单数据……
$scope.postData = {};
// 保存到服务器
$scope.newPost = function() {
var post = new Post($scope.postData);
post.$save();
//刷新列表,使用 unshift 在数组顶部插入
$scope.posts.unshift( $scope.postData);
// 重置表单
$scope.postData = {};
}
// 删除
$scope.deleteItem = function(item, idx) {
$scope.posts.splice(idx, 1);
item.$delete();
//Post.remove({id:item.Id});
}
// 排序
$scope.moveItem = function(item, fromIndex, toIndex) {
$scope.posts.splice(fromIndex, 1);
$scope.posts.splice(toIndex, 0, item);
};
});
7、自定义查询方法
// Booking Resource
service.factory("Booking", function ($resource) {
return $resource(
"/api/booking/:Id",
{Id: "@Id" },
{
"update": {method: "PUT"},
"reviews": {'method': 'GET', 'params': {'reviews_only': "true"}, isArray: true}
}
);
});
上面 reviews 是自定义方法:使用 GET,参数是 views_only=true,返回数组。
然后可以这样使用:
var reviews = Booking.reviews(); // Calls: GET /api/booking/?reviews_only=true
使用 $http
比如视图是:
<body ng-app="ionicApp" ng-controller="MainCtrl">
The weather outside is {{conditions}}
</body>
那么可以这样调用远程服务器 API
angular.module('ionicApp', [])
.controller('MainCtrl', function($scope, $http) {
$http.get('http://echo.jsontest.com/conditions/frightful').then(function(resp) {
$scope.conditions = resp.data.conditions;
}, function(err) {
console.error('ERR', err);
// err.status will contain the status code
})
});
API 文档:https://docs.angularjs.org/api/ng/service/$http
比如
$http.get('phones/phones.json').success(function(data) {
$scope.phones = data;
});
1)使用 GET 方法
$http.get('/someUrl')
.success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
})
.error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
2)使用 POST 方法
$http.post('/someUrl', {msg:'hello word!'})
.success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
})
.error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
3)或者这么配置
var req = {
method: 'POST',
url: 'http://example.com',
headers: {
'Content-Type': undefined
},
data: { test: 'test' },
}
$http(req).success(function(){...}).error(function(){...});
联系客服