angular Cache Method for post Request

problem

  • By default, angular's $http caches only the request data for "get" and "jsonp".

Source code analysis of angular $http cache

// line 11737

      if ((config.cache || defaults.cache) && config.cache !== false &&
          (config.method === 'GET' || config.method === 'JSONP')) {//Determine whether to cache
        cache = isObject(config.cache) ? config.cache
              : isObject(defaults.cache) ? defaults.cache
              : defaultCache;
          console.log('cache',cache);//Selecting Cache Objects
      }
         if (cache) {
            cachedResp = cache.get(url);//Getting Cache
            ...
        }
  • First we need to pass the config.method and config.cache checks.
  • Next, you need a unique url, which can be generated by encoding data objects using angular's own URL encoding service, $http ParamSerializer, or other methods, as long as it's unique.
  • In addition, if you simply change the get request and send it to the back end, it's really a get request. And we should send back-end post requests. Therefore, the first request must be sent to the backstage in its original form. This leads to the fact that we can only create a container to cache the data ourselves. And it's a container created by cacheFactory so that http can recognize it.

Method

  • Disguise the post request as a get request to make $http recognizable
  • Caching POST data is not difficult, mainly to enable HTTP to read post's cache and correctly execute subsequent callbacks of success and error methods. Therefore, camouflage is needed to pass http's cache validation so that the $http code can be executed.
   $http.post(url,data).then(success,error);
  • thinking

    1. New Interceptor

       var myapp=angular.module('myapp',[]);
      myapp.config(function ($httpProvider) {
        $httpProvider.interceptors.push(function ($q) {
            return {
                request:function (config) {            
                    return config
                },
                response:function (response) {
                    return response;
                }
            }
        })
      });
      
    2. Create a container for caching post data

       var cache=angular.injector(['ng']).get('$injector').get('$cacheFactory')('$httpPost');
    3. When requesting a request, determine whether it is a POST request and set cache:true. If it is, and the cache has passed the data, it masquerades as the'GET'method and passes directly if there is no cache.

       request:function (config) {
                    if(config.cache&&config.method==='POST'){
                        //Start counting
                        var url=config.url+'?'+config.paramSerializer(config.data);
                        console.log('url',url,cache.get(url));
                        if(cache.get(url)){
                            config.cache=cache;
                            config.method='GET';
                            config.url=url;
                        }
                    }
                    return config
                },
    4. When response returns, determine whether it is a POST request, and set cache:true, if so, cache it

      response:function (response) {
                    var config=response.config;
                    if(response.config.cache&&response.config.method==='POST'){
                        var url=config.url+'?'+config.paramSerializer(config.data);
                        cache.put(url,response.data);
                        console.log('save Cache',url,cache.get(url));
                    }
                    return response;
                }

Code

  • Complete demo (angular version 1.5.8)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script src="./angular.js"></script>
<div ng-app="myapp">
    <div ng-controller="myctrl">
        <span ng-bind="name"></span>
        <span ng-bind="age"></span>
        <button ng-click="load()">Load</button>
    </div>
</div>
<script>
  var myapp=angular.module('myapp',[]);
  myapp.config(function ($httpProvider) {
      $httpProvider.interceptors.push(function ($q) {
          var cache=angular.injector(['ng']).get('$injector').get('$cacheFactory')('$httpPost');
          console.info('cache',cache);
          return {
              request:function (config) {
                  if(config.cache&&config.method==='POST'){
                      //Start counting
                      var url=config.url+'?'+config.paramSerializer(config.data);
                      console.log('url',url,cache.get(url));
                      if(cache.get(url)){
                          config.cache=cache;
                          config.method='GET';
                          config.url=url;
                      }
                  }
                  return config
              },
              requestError:function (rejection) {
                  console.log('rejection',rejection);
                  return rejection;
              },
              response:function (response) {
                  var config=response.config;
                  if(response.config.cache&&response.config.method==='POST'){
                      var url=config.url+'?'+config.paramSerializer(config.data);
                      cache.put(url,response.data);
                      console.log('save Cache',url,cache.get(url));
                  }
                  return response;
              }
          }
      })
  });
  myapp.controller('myctrl',function ($scope,$http) {
      $scope.name='demo';
      $scope.age=100;
      $scope.load=function () {
          $http({
              url:'data.json',
              method:'post',
              data:{name:1},
              cache:true}).success(function (data) {
              console.log('ajax result',data);
              $scope.name=data.name;
              $scope.age=data.age;
          }).error(function (error) {
              console.error('error',error);
          });
      };
      $scope.load();
  })
</script>
</body>
</html>
  • data.json
{
  "name":"gyanxie",
  "age":"Long live long live long live long live"
}

Tags: angular encoding JSON

Posted on Tue, 09 Jul 2019 16:19:40 -0400 by regoch