Whenever my node server returns a 404 error, I want this to be intercepted by my Angular app and the user directed to a certain route.
I'm trying to build a simple interceptor to do this however it doesn't seem to return anything.
Any pointers on why this code won't print anything when the 404 is coming in (I've confirmed this by looking at the page header):
And the code:
.config(function($httpProvider) {
//Ignore this authInceptor is for saving my JWT's
$httpProvider.interceptors.push('authInterceptor');
//This is the one I'm having issue with
$httpProvider.interceptors.push(function myErrorInterceptor($window, $location) {
return {
requestError: function(res){
if (res.status === 404) {
console.log('You're In - Now do some more stuff')
}
return res;
}
}
})
})
UPDATE:
So in addition to that, i've realised on my node side - i have
//This section is to handle Angular HTML5Mode Urls
//Have to rewrite all your links to entry point of your application (e.g. index.html)
app.get('/*', function(req, res) {
res.sendFile(__dirname + '/site/index.html')
});
So another issue here is - that app.get('/*' won't be bale to distinguish between whats allowed as per Angular routes - so how do i get it be aware of that? (Don't want something an array where i duplicate code)
I believe the problem is that you are hooking into requestError instead of responseError. Try the following:
.config(function($httpProvider) {
//Ignore this authInceptor is for saving my JWT's
$httpProvider.interceptors.push('authInterceptor');
//This is the one I'm having issue with
$httpProvider.interceptors.push(function myErrorInterceptor($window, $location) {
return {
responseError: function(res){
if (res.status === 404) {
console.log('You're In - Now do some more stuff')
}
return res;
}
}
})
});
Related
I want redirect to dashboard.html from login.html if username is correct, if not then alert box will be shown, I used both express response.redirect('path') or response.sendFile('path') but none is working here.
I am using angularJs as front-end and express module of nodeJs in back-end.
Express route code:
module.exports = function(app,db,path){
app.post('/student-login', function (request, response) {
var user = request.body;
if(user.username == "abhinav")
{
response.redirect('/views/dashboard.html');
response.end();
}
else{
response.send("Wrong username");
response.end();
}
});
}
AngularJs code:
angular.module('loginService',[])
.service('loginService',function($http){
return {
sendStudent : function(data){
return $http.post('/student-login',data)
.then(function(response){
return response.data;
});
}
}
});
AngularJs controller Code:
if ($scope.myForm.$valid)
loginService.sendStudent($scope.studentData)
.then(function(data){
if(data=="Wrong username")
alert(data);
});
Developer option > Network :
As you can see in the Network tab, browser does make a request to the /views/dashboard.html route. It means that redirect is working. The reason why you don't get the expected behavior is because you need to navigate to that page (right now you are simply loading content of the page).
I would suggest moving redirection logic from express to frontend and using http status codes to signal login errors.
Express code:
module.exports = function(app,db,path){
app.post('/student-login', function (request, response) {
var user = request.body;
if (user.username == "abhinav") {
response.sendStatus(200);
} else {
response.sendStatus(401);
}
});
}
AngularJS controller code:
if ($scope.myForm.$valid) {
loginService.sendStudent($scope.studentData).then(() => {
// login successful, response status is 200
location.href = '/views/dashboard.html'
}).catch(response => {
if (response.status === 401) {
alert("Wrong username")
} else {
alert("Some other error")
}
})
}
I'm using location.href as an example only because I'm not familiar with angularjs routing. It will reload the whole page, use API provided by angularjs router if you want to avoid that.
I am currently struggling with best practices for error handling in ExpressJS routes, particularly POST routes.
I have set up the default middleware error handling and I am using return next(err); in case of any errors. This works fine for all errors in GET routes.
However, what is the best practice to handle errors in the other route types, in particular POST routes?
On the front end, I am using AngularJS and I am posting using $http. When using return next(err); in the POST route, the .error(function(data,status,headers,config) of $http is called (AngularJS) and I receive the whole html error page inside data variable.
What I am looking for is a redirect for the user to the general error page through the ExpressJS middleware in case the client-side should not handle this error. This way, I could also do my error handling and logging at one single place.
So, my current idea: In POST routes, simply do return res.status(500).send({err: err}); In case the application cannot recover, then use a redirect on client side with AngularJS to a general error page. However, I would prefer to use the ExpressJS middleware to have a central place to handle errors.
I appreciate any help or pointers to best practice articles!
For reference, the (standard) error middleware function looks like this:
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('shared/error/error', {
message: err.message,
error: err
});
});
If you're using an angular $http method to GET or POST to your server, you should be returning JSON data back to the app to parse. For example, your route:
app.get('/example', function(req, res) {
getSomeData()
.then(function(data) {
res.status(200).json(data);
}, function(err) {
res.status(400).json(err);
});
});
In your angular service, you can create a method that returns the route's data in a promise:
angularApp.service('DataService', function($http) {
this.getData = function() {
return $http.get('/example')
};
});
Then use the service in your controller like this:
angularApp.controller('MyController', function($scope, DataService) {
DataService.getData()
.then(function(response) {
$scope.data = response.data;
}, function(err) {
showErrorMessage(err.statusText);
});
});
I have an application for which I created an interceptor to handle token expirations after 15 minute inactivity, it successfully redirects to the login page after a token has expired, but Im not able to show the error after redirecting to the login page.
My question is, how can I show the user the token expired error on the login page, after the interceptor has redirected the app to that page.
Heres my redirector:
app
.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push(function($q, $location, LoopBackAuth) {
return {
responseError: function(rejection) {
if (rejection.status == 401) {
//Now clearing the loopback values from client browser for safe logout...
LoopBackAuth.clearUser();
LoopBackAuth.clearStorage();
$location.path("/login");
}
return $q.reject(rejection);
}
};
})
}])
.config(function(LoopBackResourceProvider) {
LoopBackResourceProvider.setAuthHeader('X-Access-Token');
})
Finally and thanks to #forrestmid to point me in the right direction this is what I ended up doing.
on the http interceptor just added:
$location.path("/login").search({error: 'invalid_token'});
and then on the controller just had to do:
var queryString = $location.search();
$scope.errors = {};
if (queryString && queryString.error) {
$scope.errors = {
'invalid_token': {
code: 'invalid_token'
}
}
}
now on the template I already have logic to handle the error object so now it works fine :)
Referencing this post in regards to injecting the $state service into an HTTP interceptor:
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push(function($q, $injector, LoopBackAuth) {
return {
responseError: function(rejection) {
if (rejection.status == 401) {
//Now clearing the loopback values from client browser for safe logout...
LoopBackAuth.clearUser();
LoopBackAuth.clearStorage();
$injector.get('$state').go('app.login', {error: 'Token expired.'});
}
return $q.reject(rejection);
}
};
})
}]);
Assuming that you're using ui.router:
app.config(function($stateProvider){
$stateProvider
.state("app",{abstract: true})
.state("app.login", {
url: "/login",
params: {error: ""}
});
});
By default there will be no error when transitioning to the app.login state, but when there is a param error set to whatever, it can display the error. This will be in the $stateParams.error variable on your login page.
Let me know if I botched any of that code since I didn't test it. The line I think you want is the $injector line.
Hello I am using ngResource $save method and I get two different behaviours, I don't understand why
First I'm using it in this way:
$scope.user = new User($scope.user);
$scope.user.$save(function () {
$window.location.href = //redirection here;
}, function (response) {
$scope.form.addErrors(response.data.errors);
});
Then I have another controller when I'm doing a similar operation, but even getting 404 or 422 errors from the server the first callback is executed and the errors callback is ignored.
Does anyone have any idea of this? I've been searching in Google for hours trying to find more documentation about $save but I'm still stuck with this problem.
Thank you.
Well, the problem was on an interceptor I am using to detect 401 (unauthorized errors)
here is the interceptor, notice that you must return $q.reject(response) otherwise the other callbacks are not called (in my case the error callback in ngResource.$save)
MyApp.config(function ($httpProvider) {
$httpProvider.interceptors.push(function($window, $q) {
return {
'responseError': function(response) {
if (response.status == 401) { // Unathorized
$window.location.href = 'index.html';
}
// return response; <-- I was doing this before cancelling all errors
return $q.reject(response);
}
};
});
});
I have an angularjs project. I am just wondering, how to show the user a message, if a requested view/partial is not found (HTTP 404). At the moment, angular starts the request and gets a 404 response including the error-html, but the user doesn't see any change to the website.
Add an $http interceptor (scroll down on this page) for 'responseError'
angular.module("app").config(function($provide, $httpProvider) {
// register the interceptor as a service
$provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
return {
'responseError': function(response) {
if (response.status == 404) {
// user hit a 404 -- you can check response.url to see if it matches
// your template directory and act accordingly
return responseOrNewPromise
}
return $q.reject(rejection);
}
};
});
$httpProvider.interceptors.push('myHttpInterceptor');
});