【问题标题】:Caching with AngularJs使用 AngularJs 进行缓存
【发布时间】:2015-04-04 19:31:21
【问题描述】:

目前我正在尝试缓存用户的信息。我给你们一个正在发生的事情的场景。

用户正在尝试使用帐户 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。我需要添加一些逻辑吗?

【问题讨论】:

  • 如果您将其放入 plnkr.co 的工作 Plunk 中,调试起来会容易得多。
  • 更改 $http.get('/api/me', {cache: true});到 $http.get('/api/me?rand=' + Math.random(), {cache: true});
  • 我假设 index.html 不完整?您正在使用 ng-controller="MainController as main"?
  • @YangLi 向我解释为什么我必须这样做?添加 Math.random() 的目的是什么?
  • @JoeEnzminger 是的,我正在使用 ng-controller="MainController as main",问题出在缓存上。

标签: javascript angularjs twitter-bootstrap caching


【解决方案1】:

您的应用中可能涉及两种不同的缓存。首先是您在 {cache: true}

下设置的角度缓存
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 中发送一个不同缓存头的列表,它可能并不总是有效。

防止缓存的最简单方法是向您的 url 添加一个版本,这实际上不会影响您的结果,但会诱使您的浏览器认为它是一个不同的 url。这称为Cache Busting

缓存 bust 的最简单方法是添加一个 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.' });        
};

【讨论】:

  • 这个答案太棒了,但在我接受你的答案之前,我需要问你最后一个问题。你写的最后一个例子,我在实现时遇到了错误。我的令牌有用户名有什么问题?
  • 我检查了控制台,它说的是意外令牌。我认为 是罪魁祸首。
  • 我的 只是一个占位符值,您可能需要实际将用户名变量放在那里
  • 这只是一个例子,您可以使用任何唯一标识符,而不仅仅是用户名。请记住,标识符不应是敏感数据,例如其他用户不应该知道的 userId 或电子邮件,
  • 哦,很抱歉,我需要更改我的 api 吗?为了得到那个变量?因为我想不出任何方法来使用 angular 获取用户名值
猜你喜欢
  • 1970-01-01
  • 2017-02-25
  • 2015-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-15
  • 2021-11-27
相关资源
最近更新 更多