$http Response Interceptors in AngularJS
In AngularJS, $http
interceptors provide a powerful mechanism to globally modify or handle HTTP responses before they reach the application. This is extremely useful for centralized error handling, modifying responses, or managing common tasks like setting authentication tokens.
An HTTP interceptor can be used to intercept the response or request of HTTP operations (such as GET
, POST
, etc.) and modify them or perform custom actions. This allows developers to handle HTTP requests and responses globally, ensuring consistency throughout the app.
How HTTP Interceptors Work
An HTTP interceptor is a service that can intercept both requests and responses for any $http
operations made in the AngularJS application. This is done by configuring $httpProvider
in the app’s module and registering the interceptor service.
Interceptors can manipulate both the request (before it’s sent) and the response (after it’s received). They can be used for various purposes, such as:
- Automatically adding authentication tokens to requests.
- Handling and transforming response data.
- Handling global errors (e.g., unauthorized access).
- Logging HTTP activity.
1. Creating a Response Interceptor
A response interceptor allows you to modify or handle the HTTP response before it reaches your controllers or services.
Example: A Simple Response Interceptor
angular.module('myApp', [])
.config(function($httpProvider) {
// Register a response interceptor
$httpProvider.interceptors.push('responseInterceptor');
})
.factory('responseInterceptor', function($q) {
return {
// This method will be called when the response is received
response: function(response) {
// Perform some action on the response, e.g., log it
console.log('Response Interceptor: ', response);
// Return the response object to pass the response data forward
return response;
},
// This method will be called if there is an error in the response
responseError: function(rejection) {
// Handle the error (e.g., log it, display a message)
console.error('Response Error: ', rejection);
// You can return a rejection to propagate the error
return $q.reject(rejection);
}
};
});
Explanation:
$httpProvider.interceptors.push()
: This registers the interceptor service. The interceptor is a factory function (responseInterceptor
) that returns an object withresponse
andresponseError
methods.response
: This method is triggered whenever a response is successfully received. It can be used to manipulate or log the response.responseError
: This method is triggered whenever there is an error in the response (e.g., network issues, status code errors). It allows you to handle errors globally (e.g., showing a user-friendly message, redirecting to a login page).
2. Using Interceptors for Authentication
A common use case for interceptors is handling authentication. For example, you may need to automatically add a token to the headers of each request or handle authentication errors across the app.
Example: Authentication Token Interceptor
angular.module('myApp', [])
.config(function($httpProvider) {
// Add the authentication token interceptor
$httpProvider.interceptors.push('authInterceptor');
})
.factory('authInterceptor', function($q, $window) {
return {
// Intercept requests before they are sent
request: function(config) {
// Get the token from local storage or cookies
var token = $window.localStorage.getItem('authToken');
if (token) {
config.headers['Authorization'] = 'Bearer ' + token; // Attach token
}
return config; // Return the modified config
},
// Intercept responses for error handling
responseError: function(rejection) {
if (rejection.status === 401) {
// If the response status is 401 (Unauthorized), handle the error
console.log('Authentication Error: Redirecting to login page...');
// Redirect to login or perform other actions
}
return $q.reject(rejection); // Reject the response so it can be handled by the app
}
};
});
Explanation:
request
: In this method, we check if there is an authentication token stored inlocalStorage
. If the token exists, we append it to the request headers using theAuthorization
header. This ensures the token is automatically included in every request.responseError
: If a response returns with a401 Unauthorized
status code (for example, when the token has expired), this method can be used to handle the error globally—such as redirecting the user to a login page.
3. Chaining Multiple Interceptors
AngularJS allows you to register multiple interceptors. These interceptors will be executed in the order they are added to the $httpProvider.interceptors
array.
Example: Chaining Interceptors
angular.module('myApp', [])
.config(function($httpProvider) {
// Register multiple interceptors
$httpProvider.interceptors.push('responseInterceptor');
$httpProvider.interceptors.push('loggingInterceptor');
})
.factory('responseInterceptor', function($q) {
return {
response: function(response) {
console.log('Processing response in responseInterceptor');
return response;
},
responseError: function(rejection) {
console.error('Error in responseInterceptor');
return $q.reject(rejection);
}
};
})
.factory('loggingInterceptor', function($q) {
return {
response: function(response) {
console.log('Logging response in loggingInterceptor');
return response;
},
responseError: function(rejection) {
console.log('Logging error in loggingInterceptor');
return $q.reject(rejection);
}
};
});
Here, we have two interceptors: responseInterceptor
and loggingInterceptor
. Both will process the response in the order they are added. This enables you to manage complex flows by chaining various interceptors for different tasks like logging, analytics, or error handling.
4. The Flow of HTTP Interceptors
- Request Interceptor (if defined):
- This will be invoked before a request is sent.
- HTTP Request: The HTTP request is sent to the server.
- Response Interceptor (if defined):
- This will be invoked after the response is received but before it’s passed to your application.
- Error Handling:
- If an error occurs, the responseError interceptor will be triggered.
5. Advantages of Using Interceptors
- Centralized Error Handling: You can handle errors (such as authentication failures or network issues) in one place, rather than scattering error-handling logic throughout your application.
- Code Reusability: Common tasks such as adding authentication tokens, logging, or transforming responses can be handled once and reused across your entire application.
- Global Configuration: You can modify the behavior of all HTTP requests in one place (e.g., setting default headers or adding transformations).
- Cleaner Code: Interceptors can clean up your code by separating concerns. They can handle repetitive tasks (such as appending tokens) without cluttering your controllers or services.