使用 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.' });        
};