I've made an interceptor in my application that detects session loss (server sends an HTTP 419). In this case, I need to request a new session from the server, and then I would like to send the original request again automatically.
Maybe I could save the request in a request interceptor, and then send it again, but there might be a simpler solution.
Note that I have to use a specific webservice to create the session.
angular.module('myapp', [ 'ngResource' ]).factory( 'MyInterceptor', function ($q, $rootScope) { return function (promise) { return promise.then(function (response) { // do something on success return response; }, function (response) { if(response.status == 419){ // session lost // create new session server-side // Session.query(); // then send current request again // ??? } return $q.reject(response); }); }; }).config(function ($httpProvider) { $httpProvider.responseInterceptors.push('MyInterceptor'); });
The JWT Interceptor intercepts http requests from the React app to add a JWT auth token to the HTTP Authorization header if the user is logged in and the request is to the React app's API URL ( process. env. REACT_APP_API_URL ). It's implemented as an axios request interceptor, by passing a callback function to axios.
Axios interceptors are the default configurations that are added automatically to every request or response that a user receives. It is useful to check response status code for every response that is being received.
A request interceptor is a piece of code that gets activated for every single HTTP request received by your application. Interceptors are very useful when you need to perform some common processing for every HTTP request.
You can intercept requests or responses before they are handled by then or catch . // Add a request interceptor axios.
Here is my solution using promises for those interested. Basically you need to request a new session, and wait for the response before sending a new request corresponding to the original request (using response.config). By returning the promise $http(response.config) you ensure that the response will be treated as if it was the original request.
(syntax may not be the best as I'm new to promises)
angular.module('myapp', [ 'ngResource' ]).factory( 'MyInterceptor', function ($q, $rootScope) { return function (promise) { return promise.then(function (response) { // do something on success return response; }, function (response) { if(response.status == 419){ // session lost var Session = $injector.get('Session'); var $http = $injector.get('$http'); // first create new session server-side var defer = $q.defer(); var promiseSession = defer.promise; Session.query({},function(){ defer.resolve(); }, function(){ // error defer.reject(); }); // and chain request var promiseUpdate = promiseSession.then(function(){ return $http(response.config); }); return promiseUpdate; } return $q.reject(response); }); }; }).config(function ($httpProvider) { $httpProvider.responseInterceptors.push('MyInterceptor'); });
The responseError
method of httpInterceptor
have to be like this:
responseError: function (response) { // omit the retry if the request is made to a template or other url if (response.config.apiCal === true) { if (response.status === 419) { var deferred = $q.defer(); // do something async: try to login.. rescue a token.. etc. asyncFuncionToRecoverFrom419(funcion(){ // on success retry the http request retryHttpRequest(response.config, deferred); }); return deferred.promise; } else { // a template file... return response; } } }
And the magic happens here:
function retryHttpRequest(config, deferred){ function successCallback(response){ deferred.resolve(response); } function errorCallback(response){ deferred.reject(response); } var $http = $injector.get('$http'); $http(config).then(successCallback, errorCallback); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With