I'm a little new to the Mean stack and I've been trying to experiment a bit with http requests with a mongo database that has a collection for storing feedback
I'm repeatedly getting an error of "Can't set headers after they're sent" in my console.
Here's the code for my function
module.exports.saveFeedback = function(req, res, callback) {
var newFeedback = new feedback();
newFeedback.overallAppExperience = req.body.overallAppExperience;
newFeedback.save(function(err, result) {
if (err) {
return callback(err, null);
} else {
return callback(null, result);
}
});
}
Here's the code for my route
app.post('/feedback', function(req,res){
feedback.saveFeedback(req,res, function(err,result){
if(err){
res.status(500).send(err);
return;
}
else{
res.status(200).send(result);
return;
}
});
});
Here's the code for my controller
angular.module('myApp')
.controller('feedbackController', ['$scope', '$http', function($scope,
$http){
$scope.overallAppExperience=null;
$scope.feedbackSubmit=function()
{
var data={
overallAppExperience:$scope.overallAppExperience
}
$http.post('/feedback', data)
.then(function(response){
console.log(response.data);
},function(response){
console.log(response);
})
}]);
Here's the issue - The entry I make via submitting the feedback form on the html page gets logged on to the mongo database. The same doesn't get displayed on the web console in my browser.
This is the entry in the web console and it corresponds to the error function being invoked in the promise.
Object { data: null, status: -1, headers: wd/<(), config: Object, statusText: "" }
Also, the error message in the console mentions these two lines as problematic:
One in my feedback Function (Line 8)
return callback(null,result);
And the other in my routes function (Line 8)
res.status(200).send(result);
I have read similar posts about such errors and all of them talk about something to do with the return statements. I've tried playing around with the return statements by removing them and adding them again. However, the same error persists.
Any help would be greatly appreciated.
Related
I'm writing an ionic v1/express/mongo/node app. When checking if the user is authenticated i have the following piece of code:
checkAuthentication: function(token) {
console.log(token);
return $http.get("http://validUrl/test", {
headers: {
'testingAuth': token
}
}).then(function(result) {
return result.data;
});
}
and am calling it like this:
checkAuthentication(token).then(function(response) {
console.log("testing response: " + response);
// if a valid token is already in storage = response contains "Success"(?), just $state.go to main page, else call the login() function
if (response.content === "Success") {
// $state.go main page
} else {
console.log("could not log in");
}
})
The problem is, when I get back code 401 from the server, I somehow skip the then block in the checkAuthentication function. Execution doesn't stop at a breakpoint at "return result.data", or "console.log("could not log").
Am I doing something obviously wrong? Is there something i need to do to force going into that block? Thanks for any advice.
The issue is with your error handling ! I took the liberty to modify your code and the way to do a $http call. Here is the working plunker for the same.
If you observe the $scope.login() function I've injected the service object and invoked the checkAuthentication() function which does the HTTP call.As you are using .then for http calls, angular provides provision to use two functions for success and error callbacks where your HTTP errors go when HTTP calls fail.
Here is the angular doc for the same.
In your example you don't have error callback method hence it doesn't go into your if else conditions.
var app = angular.module("App", []);
app.controller('AppCtrl', ['$rootScope', '$scope', '$http', 'Service', function($rootScope, $scope, $http, Service) {
$scope.login = function(token) {
//call the injected service in the function for HTTP call..
Service.checkAuthentication(token).then(function(response) {
console.log("testing response: " + response);
// if a valid token is already in storage = response contains "Success"(?), just $state.go to main page, else call the login() function
if (response.content === "Success") {
// $state.go main page
}
},function(error){
console.log(error);
console.log("could not log in due to error...");
});
};
}]);
//use angular services to do a http call for better code maintainability...
app.service('Service', ['$http', '$rootScope', function($http, $rootScope) {
return {
checkAuthentication: function(token) {
return $http.get("http://validUrl/test", {
headers: {
'testingAuth': token
}
});
}
};
}]);
I'm trying to implement some error handling into my MCV AngularJS application, but came across this one issue that I'm not sure how to solve.
Structure
In my AngularJS service ticketService I have the following method:
this.downloadFile = function (fileId) {
return $http.get(baseUrl + "/Downloadfile/" + fileId, { responseType: "blob" });
}
And in my controller:
$scope.downloadFile = function (fileId) {
ticketService.downloadFile(fileId)
.then(function (response) {
// Handle correct request and response
}, function (err) {
// Handle error
notify({ message: "Something went wrong: " + err.data.Message, position: "center", duration: 10000 });
})
}
Here's what I return from the backend MVC Web API method:
var error = new HttpError("Failed to find file, bla bla bla.");
return Request.CreateResponse(HttpStatusCode.NotFound, error);
Problem
My issue is that since my responseType is set to be blob, my err object is the same response type. I would believe that it should be possible for my backend service to override this response type, and respond with an object that contains some Message.
From this response, I would've thought that I could get err.data.Message, but perhaps I misunderstood this scenario?
Thank you in advance.
public HttpResponseMessage Get(int id)
{
try
{
return Request.CreateResponse(HttpStatusCode.OK, new { Status =
"OK", Message = this._myContext.GetCustomer(id) });
}
catch(Exception e)
{
return Request.CreateResponse(HttpStatusCode.Conflict, new {
Status = "NO", Message = e.ToString() });
}
}
You can return any message like "Failed to find file, bla bla bla." in Message. Then you just need to check in ajax success method like data.Message,
The $http service uses the XHR API which is not capable of changing the responseType on the fly.
You can set the status message and use that:
public ActionResult Foo()
{
Response.StatusCode = 403;
Response.StatusDescription = "Some custom message";
return View(); // or Content(), Json(), etc
}
Then in AngularJS:
$scope.downloadFile = function (fileId) {
return ticketService.downloadFile(fileId)
.then(function (response) {
// Handle correct request and response
return response.data;
}).catch(function (response) {
// Handle error
console.log(response.status);
console.log(response.statusText);
throw response;
});
};
Alternative approaches are:
Use the Fetch API which has a more powerful and flexible feature set.
Use the FileReader API and JSONparse() method to convert the Blob to a JavaScript Object.
I have a submit function, which posts some data into a server and then the server returns a response. The function is working fine. I would like, though, to catch a couple of errors during the post process. For example, if there is no connectivity to the server, return an error to the user to inform him what's going on. instead of just pressing the button and do nothing. I know I can create a function to somehow ping the server and check if it's alive but that's not what I need. I would like to have a statement in the error function and catch most of the possible errors and output an explanation to the user.
$scope.submit = function() {
var link = 'http://app.example.com/api.php';
$http.post(link, {
username: $scope.data.username,
password: $scope.data.password
}).then(function(res) {
$scope.response = res.data;
$localStorage.token = res.data;
console.log($localStorage.token);
})
.catch(function(error) {
console.error(error);
})
.finally(function() {
//do something
});
};
Solution:
$http.post(link, {
username: md5.createHash($scope.data.username),
password: md5.createHash($scope.data.password),
}).then(function(res) {
//Success Scenario
})
.catch(function(error) {
if (error.statusText == ""){
$scope.response = "Unexpected error. Make sure WiFi is on."
//When the device is not connected on the internet the response error is -1 (or any number) and the statusText is empty. So we caching that one as-well.
}
else {
$scope.response = "Error - "+error.status + " ("+error.statusText+")";
//else we display the error along with the status, for example error 500 Internal Server error.
}
})
.finally(function() {
//This function will always be called at the end. Take advantage of it :)
});
I hope it's gonna be useful for someone.
I'm using AngularJS v1.5.0. I'm on Chrome Version 55.0.2883.95. The error I'm seeing shows similar failure behavior to this SO post, although the error description for my situation just states Object.
I've created a plunker to demonstrate the error. Open the developer console at the plunker to see the resulting error.
Given the following service,
this.test = function() {
return $q(function(resolve, reject) {
var errorObject = {
httpStatusCode: 503,
error: {
code: 5030,
message: 'Oh no! Something went wrong, please try again'
}
};
reject(errorObject);
}).then(function successCallback(response) {
return response;
}).catch(function errorCallback(response) {
throw response;
});
};
AngularJS code generates the following error:
angular.js:13550 Object {httpStatusCode: 503, error: Object}
The AngularJS code in play is:
function consoleLog(type) {
var console = $window.console || {},
logFn = console[type] || console.log || noop,
hasApply = false;
// Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
// The reason behind this is that console.log has type "object" in IE8...
try {
hasApply = !!logFn.apply;
} catch (e) {}
if (hasApply) {
return function() {
var args = [];
forEach(arguments, function(arg) {
args.push(formatError(arg));
});
return logFn.apply(console, args); // Error thrown on this line
};
}
// we are IE which either doesn't have window.console => this is noop and we do nothing,
// or we are IE where console.log doesn't have apply so we log at least first 2 args
return function(arg1, arg2) {
logFn(arg1, arg2 == null ? '' : arg2);
};
Here's how I call the service:
var test = function() {
userService.test()
.then(function successCallback(responseObject) {
console.log('Beginning of then');
})
.catch(function errorCallback(errorResponseObject) {
console.log('Beginning of catch');
});
}
The error seems to be caused by the fact that I am handling the promise rejection, and then re-throwing it. If I don't catch and rethrow, I don't get the error. Why do I receive the error when catching and re-throwing?
Update: It appears that using the $q service to reject the caught promise rejection avoids the AngularJS error I was seeing. I'll use that approach for now, but would still be interested to know why throwing out of the promise catch generates the error.
Example code without the error:
this.test = function() {
return $q(function(resolve, reject) {
var errorObject = {
httpStatusCode: 503,
error: {
code: 5030,
message: 'Oh no! Something went wrong, please try again'
}
};
reject(errorObject);
}).then(function successCallback(response) {
return response;
}).catch(function errorCallback(response) {
return $q.reject(response);
});
};
This question has nothing to do with AngularJS and much more on how promises work (including AngularJS's $q).
Throwing in a .catch is bound to have issues. Axel has an excellent explanation
if you want a quick and dirty method to get an exception to the console(or other logging mechanisms) you can use this trick:
.catch((err) => setTimeout(() => throw err));
Or its es5 variant:
.catch(function (err) { setTimeout(function () {throw err},0)})
This will keep the error as is, and get it out of the promise chain, without changing it.
However, I think it's better to incorporate the way that Axel explains in his article.
I've found what I believe to be the answer to my question. Buried in this discussion on the AngularJS Github issues section, #gkalpak notes the following:
The only difference between them is that return $q.reject(anything) will just pass anything down the chain, while throw anything will additionally pass anything to the $exceptionHandler. Other than that, both methods work the same.
So, the issue as far as I understand it, is that the $exceptionHandler prints the exception to the console. Using $q.reject as I stated in my update and again below does avoid this behavior and is my recommended solution to avoiding the console error.
this.test = function() {
return $q(function(resolve, reject) {
var errorObject = {
httpStatusCode: 503,
error: {
code: 5030,
message: 'Oh no! Something went wrong, please try again'
}
};
reject(errorObject);
}).then(function successCallback(response) {
return response;
}).catch(function errorCallback(response) {
return $q.reject(response);
});
};
Update - Based on #Sanders-Eias answer below, it is bad practice to throw exceptions out of async functions in general. That statement further bolsters the $q.reject approach.
I've been writing a service in AngularJS to save some data and, if it fails, alert the user. However, after I create my resource and call $save:
myResource.$save(function(success) {
console.log(success);
}, function(error) {
console.log(error);
});
I expect the error callback's argument to be an object with data, status, headers, etc., but all I get is an object with a "then" function. I tried to mock it up in JSFiddle:
http://jsfiddle.net/RichardBender/KeS7r/1/
However, this example works as I originally expected. I yanked this JSFiddle example and put it in my project and it has the same problem I originally described, despite that as far as I can tell everything else is equal. Does anyone have any idea why this might be? My project was created with Yeoman/Bower/Grunt but I can't see why those things would make a difference here.
Thanks,
Richard
I solved the problem. The error was in my HTTP interceptor, where upon an error code, I was accidentally returning $q.reject(promise) rather than $q.reject(response).
The bugged version:
.factory('httpInterceptor', function($q) {
return function(promise) {
return promise.then(
// On success, just forward the response along.
function(response) {
return response;
},
function(response) {
// ... where I process the error
return $q.reject(promise);
}
);
};
The fixed version:
.factory('httpInterceptor', function($q) {
return function(promise) {
return promise.then(
// On success, just forward the response along.
function(response) {
return response;
},
function(response) {
// ... where I process the error
return $q.reject(response);
}
);
};
-Richard