I have function, that executes when 'dataCompiled' event fires, it looks like his:
eventEmitter.on('dataCompiled', function () {
json = JSON.stringify({
conversations: convs
});
res.json(json).end();
return;
});
But when i refreshing page, i getting error
Error: Can't set headers after they are sent.
Finally figured out, need send json directly to end function, so it'll look like that:
res.end(json);
You don't need to stringify and end a call to res.json if I'm not mistaken:
eventEmitter.on('dataCompiled', function () {
return res.json({
conversations: convs
});
});
Are you sure you're not sending more data after this call? You shouldn't have to use res.end(): http://expressjs.com/en/4x/api.html#res.end .
If there is another place in your code you're sending more data to res it will give the error message you are receiving, res.end is not fixing the underlying problem.
Related
I started to write some tests for my application and I have issues to read/get response from the server. I tried many things but nothing really worked, can someone help me please ?
// /api/checkCreds
exports.checkCreds = async function(req, res){
//validation
if(!await User.checkCreds(req.body.username, req.body.password)){
var result = {error: true, data: "Incorrect"}
res.sendStatus = 401;
return res.send(JSON.stringify(result));
}
If credentials sent to the server aren't matching, return a response with "Incorrect" message back to the user.
In the test I'm trying to get data from the server to check if properties are matching the expected output.
//test.js
it("We should fail with HTTP code 401 because incorrect data is passed (username='incorrect' password='incorrect')", function(done){
supertest(app)
.post('/api/checkCreds')
.send({username: 'incorrect', password: 'incorrect'})
.expect({error: true, data: "Incorrect"})
.expect(401, done);
});
When ran, test fails because expected properties are different from the response sent by the server, which is an empty object {}.
Any help is appreciated.
You may try changing your first expect to see if you can coax supertest into showing you the actual body that it's comparing to. For example, expect('')
If that doesn't work, there's a version of expect that accepts a function. In that function, you should be able to print out what you are getting in the response body, ie. console.log(res).
It may be that there's some confusion with the JSON return type-- I haven't used that directly. You could try expecting JSON.
Finally, there's a strange paragraph in the documentation that I don't think applies, but I thought I'd mention:
One thing to note with the above statement is that superagent now sends any HTTP error (anything other than a 2XX response code) to the callback as the first argument if you do not add a status code expect (i.e. .expect(302)).
While trying to fix my issue, I noticed that in the HTTP response, Content-Type header was set to text/plain and my server was returning JSON, so that probably was the thing that confused supertest.
I think that res.send() sets the header to text/plain by default and I had to manually set the header value to application/json by using res.type('json'). At that point I was able to read the response body without an issue.
I also learned that res.json() sets the Content-Type header to application/json by default, so you don't need to do it manually like with res.send().
Working code:
// /api/checkCreds
if(!await User.checkCreds(req.body.username, req.body.password)){
var result = {error: true, data: "Incorrect"}
return res.status(401).json(result);
}
//test.js
it("We should fail with HTTP code 401 because incorrect data is passed (username='incorrect' password='incorrect')", function(done){
supertest(app)
.post('/api/checkCreds')
.set('Content-type', 'application/json')
.send({username: 'incorrect', password: 'incorrect'})
.expect(401)
.expect(function(res){
console.log(res.body);
})
.end(done);
});
Feel free to correct me if I stated something that isn't quite right.
I have a page with file uploading/downloading functionality.
When I try to download a file AND cancel the save file prompt, which happens after the res.writeHead part, it leaves the headers and it waits for the res.write and res.end parts.
The problem is that these are escaped if the prompt is cancelled, making every other response fail with the error "Can't set headers after they are sent".
Is there anyway to end the response catching the cancelled prompt event is some way, or any other way to avoid this?
The part that sets headers and streams data for the file download (located in a function that is called in the /download/:filename route) is :
res.writeHead(200, {'Content-Type': 'application/octet-stream'});
var readstream = gfs.createReadStream({
filename: files[0].filename
});
readstream.on('data', function(data){
res.write(data);
});
readstream.on('end', function(){
res.end();
});
If this sequence is not completed, every other response fails.
example:
res.status(403).send('You have no access to this file');
in another controller, called in the same page.
(I guess if I redirected to another page headers would actually get cleared?)
*If I select download location and press ok, no error occurs
*I am not having a double response in a loop, to avoid this common mistake answer :)
in express you can check for res.headersSent, this way you would be able to avoid the exception
if(res.headersSent){
return;
} else {
//set you headers
}
Say that an error occurs when I'm in the middle of sending a chunked response from my http server that I'm writing in Node.js. There's no way to send an error message to the client at this point, and I figure that this answer is correct on what to do in this situation:
All you can do is close the connection. Either the client does not receive all of the headers, or it does not receive the terminating 0-length chunk at the end of the response. Either way is enough for the client to know that the server encountered an error during sending.
So the question is, how do I do this on my http.ServerResponse object? I can't call end, because then the client will think everything went well, and there is no close method. There is a 'close' event, but I get the feeling that's something I'm supposed to listen for in this context, not emit myself, right?
I do it in the following manner:
function respDestroy()
{
this._socket.destroy();
}
function respReply(message, close)
{
if (!close)
this.end(message);
else
this.end(message, function(){ this.destroy(); });
}
server.on('request',
function(req, resp)
{
resp._socket = resp.socket; // `socket` field is nulled after each `end()`
resp.destroy = respDestroy;
resp.reply = respReply;
...
});
You can modify respReply to accept status code and status message as well.
I'm a beginner in Express.js and I'm confused by these two keywords: res.end() and res.send().
Are they the same or different?
First of all, res.send() and res.end() are not the same.
I would like to make a little bit more emphasis on some key differences between res.end() & res.send() with respect to response headers and why they are important.
1. res.send() will check the structure of your output and set header
information accordingly.
app.get('/',(req,res)=>{
res.send('<b>hello</b>');
});
app.get('/',(req,res)=>{
res.send({msg:'hello'});
});
Where with res.end() you can only respond with text and it will not set "Content-Type"
app.get('/',(req,res)=>{
res.end('<b>hello</b>');
});
2. res.send() will set "ETag" attribute in the response header
app.get('/',(req,res)=>{
res.send('<b>hello</b>');
});
¿Why is this tag important?
The ETag HTTP response header is an identifier for a specific version of a resource. It allows caches to be more efficient, and saves bandwidth, as a web server does not need to send a full response if the content has not changed.
res.end() will NOT set this header attribute
First of all, res.send() and res.end() are different.
res.send() will send the HTTP response. Its syntax is,
res.send([body])
The body parameter can be a Buffer object, a String, an object, or an Array. For example:
res.send(new Buffer('whoop'));
res.send({ some: 'json' });
res.send('<p>some html</p>');
res.status(404).send('Sorry, we cannot find that!');
res.status(500).send({ error: 'something blew up' });
See this for more info.
res.end() will end the response process. This method actually comes from Node core, specifically the response.end() method of http.ServerResponse. It is used to quickly end the response without any data. For example:
res.end();
res.status(404).end();
Read this for more info.
res.send() implements res.write, res.setHeaders and res.end:
It checks the data you send and sets the correct response headers.
Then it streams the data with res.write.
Finally, it uses res.end to set the end of the request.
There are some cases in which you will want to do this manually, for example, if you want to stream a file or a large data set. In these cases, you will want to set the headers yourself and use res.write to keep the stream flow.
In addition to the excellent answers, I would like to emphasize here, when to use res.end() and when to use res.send() this was why I originally landed here and I didn't found a solution.
The answer is very simple.
res.end() is used to quickly end the response without sending any data.
An example for this would be starting a process on a server:
app.get(/start-service, (req, res) => {
// Some logic here
exec('./application'); // dummy code
res.end();
});
If you would like to send data in your response then you should use res.send() instead:
app.get(/start-service, (req, res) => {
res.send('{"age":22}');
});
Here you can read more:
http://expressjs.com/en/4x/api.html#res.end
http://expressjs.com/en/4x/api.html#res.send
res.send() is used to send the response to the client where res.end() is used to end the response you are sending.
res.send() automatically call res.end() So you don't have to call or mention it after res.send()
res is an HttpResponse object which extends from OutgoingMessage. res.send calls res.end which is implemented by OutgoingMessage to send HTTP response and close connection. We see code here
Following scenario:
I use Node.js to connect to an API.
I fire a request and get a jsonp response back.
This response look like:
processResponse({"LoginResponse":{"#token":"x"}})
That's it. Just that line: A string/object/text.
I have also a function processResponse()
processResponse(data){
console.log(data);
};
My Question: How to get that response executed, since it is just an object. I wish to 'parse' a string to a function call.
client.methods.loginRequest(loginArgs, function(data,response){
//response body as js object
console.log(data);
// processResponse({"LoginResponse":{"#token":"x"}})
// now I wish to execute it.
data; // this doesn't work
data.exec(); // this doesn't work
? // what else
});
function processResponse(data){
console.log(data);
};
I hope there is a way?