Ограничение HTTP-вызовов из заводской службы

Я использую службу factory для получения некоторых данных с помощью службы $http. Проблема здесь в том, что я не хочу каждый раз делать запрос http, я хочу где-то сохранить эти данные и получить их локальную копию, когда это необходимо. С этой целью я подумал создать массив внутри этого factory и присвоить ему загруженные данные при первом вызове, а затем просто вернуть их, когда это необходимо, вместо того, чтобы снова загружать их с сервера. В моем случае каждый раз запускается служба http. Как я могу это исправить? Я прочитал здесь, но это не отвечает мой вопрос.

Это мой factory:

angular.module("app").factory("getDataService", ['$http', function ($http) {
    var usersArray = [];
    if (usersArray.length === 0) {
        return {
            getJsonData: function () {
                return $http.get('https://api.myjson.com/bins/eznv3')
                    .success(function (data, status, headers, config) {
                        usersArray = data;
                        return data;
                    })
                    .error(function (error, status, headers, config) {
                    });
            }
        }
    }else{
        return usersArray;
    }
}]);

И это controller, который использует этот сервис:

angular.module("app").controller("ctrl", ["$scope", "getDataService", function ($scope, getDataService) {

    angular.element(document).ready(function () {
            getDataService.getJsonData().then(function (data) {
                $scope.users = data.data;
            });
    });
}]);

person Alex    schedule 11.01.2017    source источник
comment
То, что опубликовал @ankit, верно. Другой способ - сохранить данные в HTML sessionStorage при первом вызове и установить isCacheFlag = true. Перед тем, как попасть на сервер, вы можете проверить, является ли флаг ложным, а затем нажать на сервер, иначе вы получите ответ от сеанса или локального хранилища.   -  person Kgn-web    schedule 11.01.2017
comment
Спасибо за дополнение!! Кстати, мы тоже делаем свой собственный код, но нам приходится управлять им для каждого запроса, который мы делаем, если мы хотим кэшировать ответы на все запросы на получение. Но {cache: true} намного лучше, чем сложность кода.   -  person Ankit Vadi    schedule 11.01.2017


Ответы (3)


Вам не нужно кэшировать ответ $http.get вручную, сам angularJS предоставляет способ кэширования ответа. Попробуйте использовать приведенный ниже код в функции getJsonData вашей фабрики:

getJsonData: function () {
    return $http.get('https://api.myjson.com/bins/eznv3', {cache: true})
    .success(function (data, status, headers, config) {
          return data;
     })
     .error(function (error, status, headers, config) {
     });
}

Источник: https://docs.angularjs.org/api/ng/service/$http#get

Прочитайте вышеуказанный документ. Там вы найдете конфигурации.

person Ankit Vadi    schedule 11.01.2017

Для этого вы можете использовать Локальное хранилище — один из лучших и самых простых способов.

LocalStorage.setItem('usersArray',data); устанавливает данные в локальном хранилище.

LocalStorage.getItem('usersArray'); извлекает данные из локального хранилища.

Вот смена твоего завода,

angular.module("app").factory("getDataService", ['$http', function ($http) {
    var usersArray = LocalStorage.getItem('usersArray');
    if (usersArray.length === 0) {
        return {
            getJsonData: function () {
                return $http.get('https://api.myjson.com/bins/eznv3', {cache: true})
                    .success(function (data, status, headers, config) {
                        usersArray = data;
                        LocalStorage.setItem('usersArray',data);
                        return data;
                    })
                    .error(function (error, status, headers, config) {
                    });
            }
        }
    }else{
        return LocalStorage.getItem('usersArray');
    }
}]);

Ваш контроллер,

angular.module("app").controller("ctrl", ["$scope", "getDataService", function ($scope, getDataService) {

    var x = [];

    angular.element(document).ready(function () {
        if (x.length == 0) {
            getDataService.getJsonData().then(function (data) {
                x = data.data;
                $scope.users = x;
            });
        }else{
            console.log("local copy of data exists");
        }
    });
}]);

Преимущества локального хранилища:

  • Благодаря локальному хранилищу веб-приложения могут хранить данные локально в браузере пользователя.
  • В отличие от файлов cookie, предел хранения намного больше (не менее 5 МБ), и информация никогда не передается на сервер.
person Sravan    schedule 11.01.2017
comment
Не думаете ли вы, что ему нужно проверить, является ли локальное хранилище нулевым или нет. Если его нуль, сделайте вызов ajax, иначе обслуживайте данные из локального хранилища. - person Kgn-web; 11.01.2017
comment
Я никогда не пробовал этот вариант, поэтому, хотя все добавляют это, я не добавлял, потому что не знаю, правильно ли это. как вы сказали это, я собираюсь добавить сейчас. Спасибо за это. - person Sravan; 11.01.2017

Несколько дней назад я получил такое же требование, и ниже приведен код модуля, который я создал для того же...

'use strict';
(function() {
    angular.module('httpService', []).service("api", ["$http", "dbService", function($http, dbService) {
        /**
         * <Pankaj Badukale>
         * ()
         * request.url      => Url to request 
         * request.method   => request method
         * request.data     => request data
         * request.mask     => This is custom object for out use
         *
         * @return ()
         */
        return function (request) {
            var url         = (request != undefined && request.url != undefined) ? request.url : "./";
            var method      = (request != undefined && request.method != undefined) ? request.method : "GET";
            var rData       = (request != undefined && request.data != undefined) ? request.data : {};
            /**
             * mask is CUSTOME object we add to request object
             * Which is useful for keep track of each request as well interceptor execute
             * 
             * IT HAS
             *  {
             *      save        : true, //tell that save request response in session
             *      fetch       : true, //check local data first,
             *      fetchSource : tell about perticular source of data DEFAULT WILL BE sessionStorage
             *                    OPTIONS are session and local
             *  } strucutre FOR NOW may be it will better or enhance in future
             *
             * message property to set message in alert
             * doExecute tell wheather you want to execute maskMan code for this request
             *
             * while saving and fetching data from local it uses URL of request as key
             * maskMan is a factory which iterate your error response object and we can add different behaviours for maskMan
             */
            var mask        = {};

            if(request != undefined && request.mask != undefined) {
                mask = request.mask;
            }

            return dbService.http(request).then(function(data) {
                console.log("Data fetched from local "+ request.url);
                return data;
            }, function(err) {
                return $http({
                    url: url,
                    method: method,
                    data: rData,
                    mask: mask,
                    header:{
                            'content-type':'application/json'
                    }
                }).then(function(response) {
                    return response.data;
                },function(error) {
                    return error;
                });
            });
        };
    }]).service('customHttpInterceptor', ["$q", "maskMan", function($q, maskMan) {
        return {
            //before send request to server
            request: function(config) {                 
                    return config;
            },
            //if any found in request object
            requestError: function(rejection) {
                    return $q.reject(rejection);
            },
            //on response come to web app
            response: function(response) {              
                maskMan.responseIterator(response);
                //you to return any thing as response from here
                return response;
            },
            //if there is error in response`
            responseError: function(rejection) {                
                maskMan.statusIterator(rejection);              
                return $q.reject(rejection);
            }
        };
    }]).factory("maskMan", ["dbService", function(dbService) {
        return {
            /**
             * statusIterator
             * Iterate response object on error comes
             */
            statusIterator: function(rejection) {
                if( rejection.config.mask.doExecute == true) {
                    switch(rejection.status) {
                        case 404: this.notFound(rejection);
                            break;
                        default: this.dontKnow(rejection);
                    }   
                }
            },
            /**
             * notFound
             * Function to defined logic for 404 error code scenario's
             * Here we can defined generic as well specific request object conditions also
             */
            notFound: function(rejection) {
                var errMsg = rejection.config.mask.message || "Something wrong";

                alert(errMsg);

                rejection.stopExecute = true;//stop further execute of code flag
            },
            /**
             * dontKnow
             * For every error response this method goingt to envoke by default
             */
            dontKnow: function(maskObject) {
                console.log("Don't know what to do for "+maskObject.config.url);
            },
            /**
             * responseIterator
             * Define logic to do after response come to browser
             * 
             * @params JSON resp
             */
            responseIterator: function(resp) {
                //Logic to save data of response in session storage with mask command save
                if( resp.config.mask !== undefined && resp.config.mask.save === true ) {
                    var sdata   = JSON.stringify(resp.data);
                    var skey    = resp.config.url;

                    dbService.sinsert(skey, sdata);
                }//END
            }
        };
    }]).service("dbService", ["$q", function($q) {
        /**
         * http
         * Custom mirror promise to handle local storage options with http
         * 
         * @params JSON request
         */
        this.http = function(request) {
            var self = this;
            return $q(function(resolve, reject) {
                if( request.mask != undefined && request.mask.fetch === true ) {
                    var data = null;

                    if( request.mask.fetchSource == undefined || request.mask.fetchSource == "session") {//go for default sessionStorage
                        data = JSON.parse(self.sget(request.url));
                    } else if( request.mask.fetchSource == "local" ) {
                        data = JSON.parse(self.get(request.url));
                    } else {
                        reject( "Fetch source is not defined." );
                    }

                    if( data != undefined && data != null ) {
                        resolve(data);
                    } else {
                        reject("Data not saved in local "+request.url);
                    }
                } else {
                    reject("Data not saved in local "+request.url);
                }
            });
        }

        /** 
          * Add/Override data to local storage
          *
          * @params String key
          * @params Array/Json data
          * @params Function callback
          * 
          * @return Boolean/Function
          */
        this.insert =  function(key, data, callback) {          
            localStorage.setItem(key, data);

            if( callback != undefined ) {
                callback();
            } else {
                return true;
            }
        }

         /** 
           * Update data of local storage
           * This function generally used to data which is already exist and need to update
           * 
           * @params String key
           * @params Array/Json data
           * @params Function callback
           * 
           * @return Boolean/Function
           */
        this.update = function(key, data, callback) {
            var self = this;
            self.view(key, function(localData) {//callback function
                if( localData != undefined && localData != null ) {
                    //already some data exist on this key So need to update it
                    data = localData.push(data);
                }
                //just handover to insert
                if( callback !== undefined ) {
                    self.insert(key, data, callback);
                } else {
                    return self.insert(key, data);
                }
            });         
        }

         /**
           * Remove data from local storage on basis of key
           * 
           * @params String key
           * @return Boolean
           */
        this.remove = function(key, callback) {
                localStorage.removeItem(key);

                if( callback !== undefined ) {
                    callback();
                } else {
                    return true;
                }
        }

        /**
          * Get key data of local storage
          * @param String key
          * 
          * @return Array data WHEN all data    OR
          * @return String data WHEN key value
          */
        this.get = function(key, callback) {
            var key = key || "";
            var data = [];

            if( key == "" ) {
                //get all data
                for(var i in localStorage) {
                    data.push(JSON.parse(localStorage[i]));
                }
            } else {
                //get one key data
                data = localStorage.getItem(key);
            }

            if(callback != undefined) {
                callback(data);
            } else {
                return data;
            }
        }

        /** 
          * sinsert
          * Add/Override data to session storage
          *
          * @params String key
          * @params Array/Json data
          * @params Function callback
          * 
          * @return Boolean/Function
          */
        this.sinsert =  function(key, data, callback) {
            var key = this.encode(key);

            sessionStorage.setItem(key, data);

            if( callback != undefined ) {
                callback();
            } else {
                return true;
            }
        }

         /** 
           * supdate
           * Update data of session storage
           * This function generally used to data which is already exist and need to update
           * 
           * @params String key
           * @params Array/Json data
           * @params Function callback
           * 
           * @return Boolean/Function
           */
        this.supdate = function(key, data, callback) {
            var self = this;
            self.view(key, function(localData) {//callback function
                if( localData != undefined && localData != null ) {
                    //already some data exist on this key So need to update it
                    data = localData.push(data);
                }
                //just handover to insert
                if( callback !== undefined ) {
                    self.insert(key, data, callback);
                } else {
                    return self.insert(key, data);
                }
            });         
        }

         /**
           * sremove
           * Remove data from session storage on basis of key
           * 
           * @params String key
           * @return Boolean
           */
        this.sremove = function(key, callback) {
                var key = this.encode(key);

                sessionStorage.removeItem(key);

                if( callback !== undefined ) {
                    callback();
                } else {
                    return true;
                }
        }

        /**
          * get
          * Get key data of session storage
          * @param String key
          * 
          * @return Array data WHEN all data    OR
          * @return String data WHEN key value
          */
        this.sget = function(key, callback) {
            var key = key || "";
            var data = [];

            if( key == "" ) {
                //get all data
                for(var i in sessionStorage) {
                    data.push(JSON.parse(sessionStorage[i]));
                }
            } else {
                //get one key data
                key = this.encode(key);

                data = sessionStorage.getItem(key);
            }

            if(callback != undefined) {
                callback(data);
            } else {
                return data;
            }
        }

        /**
          * encode
          * encode give string using javascript
          *
          * @param String str
          * @return String
          */        
        this.encode = function(str) {
            return btoa(str);
        }

        /**
          * decode
          * decode give string using javascript
          *
          * @param String str
          * @return String
          */                
        this.decode = function(str) {
            return atob(str);
        }

        return this;

    }]).config(['$httpProvider', function($httpProvider) {
            $httpProvider.interceptors.push('customHttpInterceptor');
    }]);
})();

Как это использовать::

Включите этот модуль в свой проект....

Затем всегда используйте "httpService" для HTTP-запросов, все для вызовов API...

Нам нужно передать объект конфигурации в эту службу, чтобы рассказать о вызове API и о том, что с ним делать.... Вы можете найти подробности о конфигурации в самом коде...

Итак, как использовать в контроллере ..

module.controller('nameofController', ['httpService', function(httpService)  {
    httpService({
        url: 'Your API url',
        method: 'GET',
        mask: {
                  save        : true, //tell that save request response in session
                  fetch       : true, //check local data first before next fetch,
                  fetchSource : tell about perticular source of data DEFAULT WILL BE sessionStorage OPTIONS are session and local
             }
    }).then(function(data) {
        // promise is all same as $http
        console.log(data);
    });
}]);

Надеюсь, это поможет... Вы также можете использовать очень простое решение, чтобы просто отметить

{cache: true}

... Но это решение полностью кастомизировано и находится под полным контролем

Исходный код, который использовался в производстве, находится по адресу

person Pankaj Badukale    schedule 11.01.2017