使用 AngularJs 进行缓存
Caching with AngularJs
目前我正在尝试缓存用户信息。我给你们一个正在发生的事情的场景。
用户正在尝试使用帐户 A 登录。帐户 A 的名称出现在导航栏上。在该用户注销并尝试使用帐户 B 登录后,在导航栏本身上,该名称仍然属于帐户 A 的名称。
代码
service.js
.factory('Auth', function($http, $q, AuthToken) {
// create auth factory object
var authFactory = {};
// log a user in
authFactory.login = function(username, password) {
// return the promise object and its data
return $http.post('/api/login', {
username: username,
password: password
})
.success(function(data) {
AuthToken.setToken(data.token);
return data;
});
};
// log a user out by clearing the token
authFactory.logout = function() {
// clear the token
AuthToken.setToken();
};
// check if a user is logged in
// checks if there is a local token
authFactory.isLoggedIn = function() {
if (AuthToken.getToken())
return true;
else
return false;
};
// get the logged in user
authFactory.getUser = function() {
if (AuthToken.getToken())
return $http.get('/api/me', {cache: true});
else
return $q.reject({ message: 'User has no token.' });
};
// return auth factory object
return authFactory;
})
// ===================================================
// factory for handling tokens
// inject $window to store token client-side
// ===================================================
.factory('AuthToken', function($window) {
var authTokenFactory = {};
// get the token out of local storage
authTokenFactory.getToken = function() {
return $window.localStorage.getItem('token');
};
// function to set token or clear token
// if a token is passed, set the token
// if there is no token, clear it from local storage
authTokenFactory.setToken = function(token) {
if (token)
$window.localStorage.setItem('token', token);
else
$window.localStorage.removeItem('token');
};
return authTokenFactory;
})
// ===================================================
// application configuration to integrate token into requests
// ===================================================
.factory('AuthInterceptor', function($q, $location, AuthToken) {
var interceptorFactory = {};
// this will happen on all HTTP requests
interceptorFactory.request = function(config) {
// grab the token
var token = AuthToken.getToken();
// if the token exists, add it to the header as x-access-token
if (token)
config.headers['x-access-token'] = token;
return config;
};
// happens on response errors
interceptorFactory.responseError = function(response) {
// if our server returns a 403 forbidden response
if (response.status == 403)
$location.path('/login');
// return the errors from the server as a promise
return $q.reject(response);
};
return interceptorFactory;
});
controller.js
angular.module('mainCtrl', [])
.controller('MainController', function($rootScope, $location, Auth) {
var vm = this;
// get info if a person is logged in
vm.loggedIn = Auth.isLoggedIn();
// check to see if a user is logged in on every request
$rootScope.$on('$routeChangeStart', function() {
vm.loggedIn = Auth.isLoggedIn();
// get user information on page load
Auth.getUser()
.then(function(data) {
vm.user = data.data;
});
});
// function to handle login form
vm.doLogin = function() {
vm.processing = true;
// clear the error
vm.error = '';
Auth.login(vm.loginData.username, vm.loginData.password)
.success(function(data) {
vm.processing = false;
// get user information on page load
Auth.getUser()
.then(function(data) {
vm.user = data.data;
});
// if a user successfully logs in, redirect to users page
if (data.success)
$location.path('/');
else
vm.error = data.message;
});
};
// function to handle logging out
vm.doLogout = function() {
Auth.logout();
$location.path('/logout');
};
});
index.html
<ul class="nav navbar-nav navbar-right">
<li ng-if="!main.loggedIn"><a href="/login">Login</a></li>
<li ng-if="main.loggedIn"><a href="#">Hello {{ main.user.username }}</a></li>
<li ng-if="main.loggedIn"><a href="#" ng-click="main.doLogout()">Logout</a></li>
<li><a href=""><button class="btn btn-primary">Write</button></a></li>
</ul>
所以基本上我对问题的假设在于我添加 cache: true 的 service.js。我需要添加一些逻辑吗?
您的应用中可能涉及两种不同的缓存。首先是您在 {cache: true}
下面设置的 angular 缓存
authFactory.getUser = function() {
if (AuthToken.getToken())
return $http.get('/api/me', {cache: true});
else
return $q.reject({ message: 'User has no token.' });
};
此缓存仅在应用运行期间存在,一旦您离开或重新加载页面,它就会消失!
另一个缓存是浏览器缓存,处理起来稍微复杂一些。请注意,这与 Angular 缓存没有关系,因此如果这是您的问题,只需关闭 {cache: false} 将无济于事。为了防止缓存,您需要在您的 restful API 中发送不同缓存的列表 headers 并且它可能并不总是有效。
防止缓存的最简单方法是向您的 url 添加一个版本,它实际上不会影响您的结果,但会诱使您的浏览器认为它是一个不同的 url。这被称为 Cache Busting.
清除缓存最简单的方法是添加 Math.Random() 以附加到 url。 Math.Random 相同的机会可能有数十亿。
authFactory.getUser = function() {
if (AuthToken.getToken())
return $http.get('/api/me?rand=' + Math.random(), {cache: true});
else
return $q.reject({ message: 'User has no token.' });
};
但是,如果您想要一种更好的方法来针对您的应用执行此操作,您可以将用户名附加到您的 url。这样它将为相同的用户缓存,这意味着您实际上是在利用缓存机制而不是被它束缚!
authFactory.getUser = function() {
if (AuthToken.getToken())
return $http.get('/api/me?user=' + <username>, {cache: true});
else
return $q.reject({ message: 'User has no token.' });
};
目前我正在尝试缓存用户信息。我给你们一个正在发生的事情的场景。
用户正在尝试使用帐户 A 登录。帐户 A 的名称出现在导航栏上。在该用户注销并尝试使用帐户 B 登录后,在导航栏本身上,该名称仍然属于帐户 A 的名称。
代码
service.js
.factory('Auth', function($http, $q, AuthToken) {
// create auth factory object
var authFactory = {};
// log a user in
authFactory.login = function(username, password) {
// return the promise object and its data
return $http.post('/api/login', {
username: username,
password: password
})
.success(function(data) {
AuthToken.setToken(data.token);
return data;
});
};
// log a user out by clearing the token
authFactory.logout = function() {
// clear the token
AuthToken.setToken();
};
// check if a user is logged in
// checks if there is a local token
authFactory.isLoggedIn = function() {
if (AuthToken.getToken())
return true;
else
return false;
};
// get the logged in user
authFactory.getUser = function() {
if (AuthToken.getToken())
return $http.get('/api/me', {cache: true});
else
return $q.reject({ message: 'User has no token.' });
};
// return auth factory object
return authFactory;
})
// ===================================================
// factory for handling tokens
// inject $window to store token client-side
// ===================================================
.factory('AuthToken', function($window) {
var authTokenFactory = {};
// get the token out of local storage
authTokenFactory.getToken = function() {
return $window.localStorage.getItem('token');
};
// function to set token or clear token
// if a token is passed, set the token
// if there is no token, clear it from local storage
authTokenFactory.setToken = function(token) {
if (token)
$window.localStorage.setItem('token', token);
else
$window.localStorage.removeItem('token');
};
return authTokenFactory;
})
// ===================================================
// application configuration to integrate token into requests
// ===================================================
.factory('AuthInterceptor', function($q, $location, AuthToken) {
var interceptorFactory = {};
// this will happen on all HTTP requests
interceptorFactory.request = function(config) {
// grab the token
var token = AuthToken.getToken();
// if the token exists, add it to the header as x-access-token
if (token)
config.headers['x-access-token'] = token;
return config;
};
// happens on response errors
interceptorFactory.responseError = function(response) {
// if our server returns a 403 forbidden response
if (response.status == 403)
$location.path('/login');
// return the errors from the server as a promise
return $q.reject(response);
};
return interceptorFactory;
});
controller.js
angular.module('mainCtrl', [])
.controller('MainController', function($rootScope, $location, Auth) {
var vm = this;
// get info if a person is logged in
vm.loggedIn = Auth.isLoggedIn();
// check to see if a user is logged in on every request
$rootScope.$on('$routeChangeStart', function() {
vm.loggedIn = Auth.isLoggedIn();
// get user information on page load
Auth.getUser()
.then(function(data) {
vm.user = data.data;
});
});
// function to handle login form
vm.doLogin = function() {
vm.processing = true;
// clear the error
vm.error = '';
Auth.login(vm.loginData.username, vm.loginData.password)
.success(function(data) {
vm.processing = false;
// get user information on page load
Auth.getUser()
.then(function(data) {
vm.user = data.data;
});
// if a user successfully logs in, redirect to users page
if (data.success)
$location.path('/');
else
vm.error = data.message;
});
};
// function to handle logging out
vm.doLogout = function() {
Auth.logout();
$location.path('/logout');
};
});
index.html
<ul class="nav navbar-nav navbar-right">
<li ng-if="!main.loggedIn"><a href="/login">Login</a></li>
<li ng-if="main.loggedIn"><a href="#">Hello {{ main.user.username }}</a></li>
<li ng-if="main.loggedIn"><a href="#" ng-click="main.doLogout()">Logout</a></li>
<li><a href=""><button class="btn btn-primary">Write</button></a></li>
</ul>
所以基本上我对问题的假设在于我添加 cache: true 的 service.js。我需要添加一些逻辑吗?
您的应用中可能涉及两种不同的缓存。首先是您在 {cache: true}
下面设置的 angular 缓存authFactory.getUser = function() {
if (AuthToken.getToken())
return $http.get('/api/me', {cache: true});
else
return $q.reject({ message: 'User has no token.' });
};
此缓存仅在应用运行期间存在,一旦您离开或重新加载页面,它就会消失!
另一个缓存是浏览器缓存,处理起来稍微复杂一些。请注意,这与 Angular 缓存没有关系,因此如果这是您的问题,只需关闭 {cache: false} 将无济于事。为了防止缓存,您需要在您的 restful API 中发送不同缓存的列表 headers 并且它可能并不总是有效。
防止缓存的最简单方法是向您的 url 添加一个版本,它实际上不会影响您的结果,但会诱使您的浏览器认为它是一个不同的 url。这被称为 Cache Busting.
清除缓存最简单的方法是添加 Math.Random() 以附加到 url。 Math.Random 相同的机会可能有数十亿。
authFactory.getUser = function() {
if (AuthToken.getToken())
return $http.get('/api/me?rand=' + Math.random(), {cache: true});
else
return $q.reject({ message: 'User has no token.' });
};
但是,如果您想要一种更好的方法来针对您的应用执行此操作,您可以将用户名附加到您的 url。这样它将为相同的用户缓存,这意味着您实际上是在利用缓存机制而不是被它束缚!
authFactory.getUser = function() {
if (AuthToken.getToken())
return $http.get('/api/me?user=' + <username>, {cache: true});
else
return $q.reject({ message: 'User has no token.' });
};