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
-
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; } } }) });
-
Create a container for caching post data
var cache=angular.injector(['ng']).get('$injector').get('$cacheFactory')('$httpPost');
-
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 },
-
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:, 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" }