How to throw error from 'reponse' function of $httpProvider interceptor - javascript

I am making a http interceptor in angular and I want to make throw error from response of $httpProvider interceptor.
As per the documentation:
response: interceptors get called with http response object. The function is free to modify the response object or create a new one. The function needs to return the response object directly, or as a promise containing the response or a new response object.
responseError: interceptor gets called when a previous interceptor
threw an error or resolved with a rejection.
I want to do the bold part in above quote so that a response with status 200 (I've a condition there) is routed to responseError where I will handle the error.
Not returning a response throws following error:
Cannot read property 'data' of undefined
I do not want to return the response but want to pass it to next handler i.e responseError.
How can I do that?
I hope I made it clear.
Thanks.
Update (Code Below):
app.config(['$httpProvider', function($httpProvider) {
interceptor.$inject = ['$q', '$rootScope'];
$httpProvider.interceptors.push(interceptor);
function interceptor($q, $rootScope) {
return {
response: response,
responseError: responseError
};
function response(response) {
if (response.data.rs == "F") {
// I want to route it responseError -->
} else {
return response;
}
}
function responseError(response) {
// I want to handle that error here
}
}
}]);

Use:
return $q.reject(response);
Also make sure you return: (Read about it here)
return response || $q.when(response);
instead of:
return response;

Related

Axios: How to intercept and respond to axios request

Is there a way to not just intercept but also respond to an axios request before it has been sent off? As in, send a request from the browser and respond to it from the browser + prevent it from sending request.
I know that I can use axios interceptors to intercept the request and response before it is sent and returned to the component and I know that in the request interceptor I can throw an error and trigger the response interceptor with a failed request. How can I do the same for a successful request? Given certain conditions I want axios to respond as if it passed to the server when it actually never made it past the interceptor. is this possible?
Here's pseudo code for what I've got so far:
axios.interceptors.request.use(
request => {
if (localResponse) {
throw { isLocal: true, data: { hello: 'world' } }; // <- this will stop request and trigger
// response error. I want to trigger
// the actual response callback
} else {
return request; // <- will perform full request
}
},
error => {
return Promise.reject(error);
}
);
axios.interceptors.response.use(
response => {
return response; // <- I want to trigger this callback
},
error => { // <- so far i can only trigger a response error
if (error?.isLocal) {
return Promise.resolve(error.data);
}
return Promise.reject(error);
}
);
I've tried just resolving the request interceptor but that tries to continue to fulfill the request. Does anyone have any creative ideas for solving this problem? Maybe there's a better solution than using interceptors?
Managed to compose a solution myself. This way all my axios calls will not have to be altered, i can just change behavior of interceptor.
NOTE: If anyone comes up with a better solution I will happily tag their answer as correct and upvote. For now this is the best solution I can come up with.
SOLUTION
Here's how i was able to resolve the problem
axios.interceptors.request.use(
request => {
if (localResponse) {
throw { isLocal: true, data: { hello: 'world' } }; // <- this will stop request and trigger
// response error. I want to trigger
// the actual response callback
} else {
return request; // <- will perform full request
}
},
error => {
return error?.isLocal
? Promise.resolve(error); // <- triggers response intercept
: Promise.reject(error);
}
);
axios.interceptors.response.use(
response => {
return response;
},
error => {
error?.isLocal
? Promise.resolve(error); // <- sends as successful response
: Promise.reject(error);
}
);
Essentially what I'm doing is throwing an error to prevent the request from going through, but then resolving the error instead of rejecting it. It's a little hacky but it gets the job done.
Can you just skip the request altogether in the local scenario?
function getData() {
if (localResponse) {
return Promise.resolve({ isLocal: true, data: { hello: 'world' }});
}
else {
return axios.whatever;
}
}
...
getData().then(...)

Angular interceptor - get message from 500 error

I'm using an Angular Interceptor and I want to get the message from 500 errors (internal server error).
The problem is, that I'm getting the whole HTML in the rejection.data in responseError inside Interceptor (screenshot below).
I read that I have to configure web.config but I'm still getting the whole HTML. I just want to get the message.
Is it possible to do that?
Angular Interceptor:
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push(function ($q, $rootScope) {
return {
request: function (config) {
//the same config / modified config / a new config needs to be returned.
return config;
},
requestError: function (rejection) {
//Initializing error list
if ($rootScope.errorList == undefined) {
$rootScope.errorList = [];
}
$rootScope.errorList.push(rejection.data);
//It has to return the rejection, simple reject call doesn't work
return $q.reject(rejection);
},
response: function (response) {
//the same response/modified/or a new one need to be returned.
return response;
},
responseError: function (rejection) {
//Initializing the error list
if ($rootScope.errorList == undefined) {
$rootScope.errorList = [];
}
//Adding to error list
$rootScope.errorList.push(rejection.data);
//It has to return the rejection, simple reject call doesn't work
return $q.reject(rejection);
}
};
});
}]);
Web.Config
<system.webServer>
<httpErrors existingResponse="PassThrough" errorMode="Detailed"></httpErrors>
</system.webServer>
Edit:
I want to get the Message from the exception snapshot
I want to get the message from 500 errors (internal server error).
Use response.statusText to get the message:
responseError: function (errorResponse) {
//Initializing the error list
if ($rootScope.errorList == undefined) {
$rootScope.errorList = [];
}
//Adding to error list
$rootScope.errorList.push(errorResponse.statusText);
//It has to return the rejection, simple reject call doesn't work
return $q.reject(errorResponse);
}
From the Docs:
The response object has these properties:
data – {string|Object} – The response body transformed with the transform functions.
status – {number} – HTTP status code of the response.
headers – {function([headerName])} – Header getter function.
config – {Object} – The configuration object that was used to generate the request.
statusText – {string} – HTTP status text of the response.
-- AngularJS $http Service API Reference -- General Usage

Angular $httpProvider Interceptor and $resource

I have a simple Interceptor in angular that intercepts requests and adds a authorization header. It also intercepts a response error of 401 to know if the request failed because of authorization.
Unfortunately it seems to mess with $resource, because my $resource calls ALWAYS return the success callback and never an error (be it 400 or 500 whatever).
It's definitly the interceptor, because if I remove it, the $resource calls return with the correct callback.
Any ideas on how to fix this behavior?
Here's the interceptors request:
function request(config) {
var token = 'whatever-my-token-is';
if (token) {
config.headers.authorization = token;
}
return config;
}
And the responseError:
function responseError(response) {
if (response.status === 401) {
$rootScope.$broadcast('unauthorized');
}
return response;
}
Any help appreciated
I think you need to use a promise to return the error.
adding $q to your Interceptor factory.
like so
$provide.factory('MyHttpInterceptor', function ($q){
...
})
and then have the responseError()
function responseError(response) {
if (response.status === 401) {
$rootScope.$broadcast('unauthorized');
}
return $q.reject(response);
}
this link might help also https://djds4rce.wordpress.com/2013/08/13/understanding-angular-http-interceptors/

How to intercept all http requests using AngularJS?

My Question is a bigger and broader version of this question. I want to intercept all http requests issued inside an AngularJS function. Later I need to alter the request URL and than pass it to the server..
How can I do that ? So far I have used $httpProvider and $q to create a interceptor but I am only able to intercept only $http requests not all the requests i.e. if someone clicks on any href link on my page etc. My interceptor code is :-
// register the interceptor as a service
myModule.factory('myHttpInterceptor', function ($q) {
return {
// optional method
'request': function (config) {
// do something on success
console.log("request success");
return config;
},
// optional method
'requestError': function (rejection) {
// do something on error
console.log("Request Error");
if (canRecover(rejection)) {
return responseOrNewPromise
}
return $q.reject(rejection);
},
// optional method
'response': function (response) {
// do something on success
console.log("Response received");
return response;
},
// optional method
'responseError': function (rejection) {
// do something on error
if (canRecover(rejection)) {
return responseOrNewPromise
}
return $q.reject(rejection);
}
};
});
myModule.factory('myInterceptor', ['$log', function ($log) {
$log.debug('$log is here to show you that this is a regular factory with injection');
var myInterceptor = {
};
return myInterceptor;
}]);
myModule.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push('myHttpInterceptor');
}]);
Intercepting navigation to other pages is different from intercepting http requests. Maybe what you want is to intercept $location changes.
Have a read through this. You can do it but it depends on where the location changes are to.
http://uiadventures.wordpress.com/2013/09/06/routechange-angularjs/

Angular.js Passing error message from service to controller $scope

I am doing a http.post request and I am trying to display error message in case anything goes wrong. I am handling the error message in the service, then passing it to the controller and setting it in the $scope. I do not get any JS errors.... any ideas why that would be?
services.js
angular.module('app.services', [])
.factory('Model', function($http) {
Model.save = function(data) {
return $http.post(url, data)
.success(function(data, status, headers) {
console.log(data);
console.log(status);
console.log(headers);
})
.error(function(data, status, headers) {
var requestError = 'Something went wrong! :(';
return requestError; //pass error message back to $scope
});
}
return Model;
});
controllers.js
.controller('Ctrl', function($scope, Model) {
//form object data
$scope.formInfo = {};
//form save
$scope.saveData = function() {
//console.log($scope.formInfo);
$scope.requestError = '';
//form data
var data = {name: $scope.formInfo.name, description: $scope.formInfo.description, token: "/api/v1/tokens/1/"};
Model.save(data).then(function(requestError) {
alert(requestError);
if (requestError === '') {
//do nothing for now
}
else {
$scope.requestError = requestError;
}
});
};
})
A promise has two end states: resolved (success) or rejected (error).
In the controller, the then() function needs two different handlers if you want to access both states. The first handler only receives resolved (success) promises from the service. To also handle rejected (error) promises from the service, you'll need something like this:
Model.save(data).then(function(success) { ... }, function(error) { ... });
If you only care about the errors for some reason, use either of these (which are equivalent):
Model.save(data).then(null, function(error) { ... });
Model.save(data).catch(function(error) { ... });
In your service, make sure you're actually returned a rejected (error) promise back to the controller in the event of an error. You do this by using return $q.reject(requestError) instead of just return requestError.
Important note: Since you're using $http, this will already reject promises in the case of an HTTP error. If you don't handle rejected (error) promises in the service, they'll automatically be passed through to the controller's error handler. You may want to simply let $http's rejection pass through, and not have an error handler in the service. You can do this by simply removing .error() in the service. This allows the HTTP error to be handled by the controller directly. (This may or may not be desirable, depending on what kind of error handling you want to do).
The basic pattern I tend to follow with my HTTP services looks like this, which returns either a resolved promise with just the downloaded data, or returns the rejected promise (error) that comes out of $http directly to the controller:
return $http.get(config).then(function(success) { return success.data });

Categories