Simple Hello World Issue in Node.js - node.js

I'm new to node.js and have this very simple code. I just want to say a Hi User every second to the users who have connected to the server.
Here's the code I have:
var http = require('http');
function newfunc(request, response) {
response.writeHead(200, {
"Content-Type": "text/plain",
"connection" : "keep-alive"
});
setInterval(function() {
response.write('Hi User\n');
response.end('');
}, 1000);
}
http.createServer(newfunc).listen(7070);
I see the Hi User message only once, and seems as if setInterval is writing it only once.
What am I doing wrong in this?

EDIT: I stand corrected in the comments... Just remove the response.end() call and you should see something like what you were expecting.
ORIGINAL RESPONSE: What you are trying to do cannot be done in this fashion... The response to an HTTP request is only ever sent once: when response.end() is called (the first time). Commenter points out that this is not really correct: what would be correct to say is that no further data can be sent in the response after end() is called.
If you want to show an HTML page whose contents change every second based on server-side actions, you will need to use something like WebSockets (e.g. the Node-compatible http://socket.io/ library) and some client-side Javascript, which is somewhat more complicated than the code you have above. In general, for non-trivial UI's that do more than just append to the response or do bi-directional communication, this type of approach is preferrable

Related

typescript fetch response streaming

i am trying to stream a response. But i want to be able to read the response (and work with the data) while it is still being sent. I basically want to send multiple messages in one response.
It works internally in node.js, but when i tried to do the same thing in typescript it doesnt work anymore.
My attempt was to do the request via fetch in typescript and the response is coming from a node.js server by writing parts of the response on the response stream.
fetch('...', {
...
}).then((response => {
const reader = response.body.getReader();
reader.read().then(({done, value}) => {
if (done) {
return response;
}
console.log(String.fromCharCode.apply(null, value)); //just for testing purposes
})
}).then(...)...
On the Node.js side it basically looks like this:
// doing stuff with the request
response.write(first_message)
// do some more stuff
response.write(second_message)
// do even more stuff
response.end(last_message)
In Node.js, like i said, i can just read every message once its sent via res.on('data', ...), but the reader.read in typescript only triggers(?) once and that is when the whole response was sent.
Is there a way to make it work like i want, or do i have to look for another way?
I hope it is kinda understandable what i want to do, i noticed while writing this how much i struggled explaining this :D
I found the problem, and as usual it was sitting in front of the pc.
I forgot to write a header first, before writing the response.

Asychronous IO operation by Node

I am new to node.js. I am creating a async operation in node with http server module. I want to print hello first and world after 5 seconds on a web page. I have referred this example form Introduction from node js by Ryan Dahl which is 8 years old.
I was wondering whether I have missed anything or something has changed in node.
I have tried with setTimeout and setInterval function but both dosent seem to work.
var http = require('http');
var server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' })
res.write('Hello \n');
setTimeout(() => {
res.end('World');
},5000)
})
server.listen(8000);
Expected result : Hello prints first followed by world after 5 seconds.
Actual result : Both Hello World prints together after 5 seconds.
Conceptually you are mixing up client and server.
The browser can only render your page when it receives the entire page. (not entirely true*, but you should think of it this way).
If you don't res.end (or res.send with express), the server will hold onto the message(see caveat below). The browser will never render no matter how many .writes you have, because it simply doesn't have the final webpage to render.
Anyway your async code is correct. If you want to see whether the asynchronity is working on the server, use console.logs instead. Whether the .write is actually sent is honestly dependent on many optimization factors you can't see.
*This is actually quite dependent on OS behavior.
https://nodejs.org/api/http.html#http_response_write_chunk_encoding_callback
Observe the API, it may or may not flush the chunk to OS. If its too small, it will usually not be flushed (for performance reasons). The OS then may or may not flush the chunk out (also for performance reasons).
If you want to see this behavior, write a much much much bigger string.
Literally this big:
var server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' })
res.write('HelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHello');
res.write('HelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHello');
res.write('HelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHello');
res.write('HelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHello');
res.write('HelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHelloHello');
setTimeout(() => {
res.end('World');
},5000)
})
You're getting Hello and world printed on the screen after 5 seconds because the res.end would be the function fired last irrespective of where or how you write it. This is because the res.end function terminates the servers response and only one response can go to the client the way you have configured.
If you truly want to see the output you desire try using console.log instead of res.end and res.write.

Bot framework async issues

I'm experimenting with the translation service on the Microsoft bot framework. I've written a method to which I pass a callback function which receives my translated text.
I've got an existing bot that calls an HTTP endpoint to create my output in English. I want to translate the output to the different language before returning it to the user. My unaltered code looks like this:
await request.post(ENDPOINT,
{
headers: HEADERS,
json: BODY
},
async function (error, response, body) {
if (response.statusCode == 202) {
var msg = body.mainResponse.text;
context.sendActivity(msg);
}
});
This runs just fine. Data passed in the HTTP response body gets parsed sent back to the user.
Now I want to plug in my translation service. I've got a single function that I call to do this called Translator.translate(text, callback). I've added this call to my existing function to get:
await request.post(ENDPOINT,
{
headers: HEADERS,
json: BODY
},
async function (error, response, body) {
if (response.statusCode == 202) {
var msg = body.mainResponse.text;
await Translator.translate(msg, function (output) {
context.sendActivity(output);
});
}
}
);
My translation process runs and I get the translation in the output variable, but nothing gets sent back to the user. Looking at the terminal, I see the error "Cannot perform 'get' on a proxy that has been revoked" relating to the context.sendActivity line in my callback.
Can anyone suggest how I keep the context object active?
Thanks in advance.
Many thanks for the assistance everyone - I never completely got to the bottom of this, but I finally fixed it with a complete re-write of the code. I think the problem was caused by a large number of nested synchronous and asynchronous calls. My ultimate solution was to completely get rid of all the nesting - first calling the translation service (and waiting for it), then doing the original call.
I think there are a number of other asynchronous threads inside the methods of both pieces of functionality. I don't have a great understanding of how this works in node, but I'm guessing that the response was getting popped off the stack at the wrong point, which is why I wasn't seeing it. The "cannot perform get" error was a bit of a red herring, it turns out. I get the same error from some of Microsoft's working demo code. I'm sure there's a separate issue there that ought to be fixed, but it wasn't actually caused by this issue. The code was running, but the output was getting lost.

Why can't we do multiple response.send in Express.js?

3 years ago I could do multiple res.send in express.js.
even write a setTimeout to show up a live output.
response.send('<script class="jsbin" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>');
response.send('<html><body><input id="text_box" /><button>submit</button></body></html>');
var initJs = function() {
$('.button').click(function() {
$.post('/input', { input: $('#text_box').val() }, function() { alert('has send');});
});
}
response.send('<script>' + initJs + '</script>');
Now it will throw:
Error: Can't set headers after they are sent
I know nodejs and express have updated. Why can't do that now? Any other idea?
Found the solution but res.write is not in api reference http://expressjs.com/4x/api.html
Maybe you need: response.write
response.write("foo");
response.write("bar");
//...
response.end()
res.send implicitly calls res.write followed by res.end. If you call res.send multiple times, it will work the first time. However, since the first res.send call ends the response, you cannot add anything to the response.
response.send sends an entire HTTP response to the client, including headers and content, which is why you are unable to call it multiple times. In fact, it even ends the response, so there is no need to call response.end explicitly when using response.send.
It appears to me that you are attempting to use send like a buffer: writing to it with the intention to flush later. This is not how the method works, however; you need to build up your response in code and then make a single send call.
Unfortunately, I cannot speak to why or when this change was made, but I know that it has been like this at least since Express 3.
res.write immediately sends bytes to the client
I just wanted to make this point about res.write clearer.
It does not build up the reply and wait for res.end(). It just sends right away.
This means that the first time you call it, it will send the HTTP reply headers including the status in order to have a meaningful response. So if you want to set a status or custom header, you have to do it before that first call, much like with send().
Note that write() is not what you usually want to do in a simple web application. The browser getting the reply little by little increases the complexity of things, so you will only want to do it it if it is really needed.
Use res.locals to build the reply across middleware
This was my original use case, and res.locals fits well. I can just store data in an Array there, and then on the very last middleware join them up and do a final send to send everything at once, something like:
async (err, req, res, next) => {
res.locals.msg = ['Custom handler']
next(err)
},
async (err, req, res, next) => {
res.locals.msg.push('Custom handler 2')
res.status(500).send(res.locals.msg.join('\n'))
}

How to end an express.js / node POST response?

Im trying to just stop the post request after I've saved a document to the DB, ie:
app.post('/blah'), function(req,res){
//my code does a bunch of stuff
res.what do i put here to tell the client browser to just... stop the POST
}
At the moment im simply using res.redirect('back') which works, but the page refresh is totally arbitrary and i would prefer it didnt happen. I had a go at res.end(); but that sends the client to a blank page...
Thanks in advance.
edit:
I dont think i made myself clear enough in what im doing sorry.
Perhaps its bad practice but this is whats happening:
POST initiates database save function
Browser sits around waiting for a response
When its good and ready, the obj is saved to the DB, then a callback triggers a NowJS function, which adds the item to the view(for everyone)
I did it this way to be non-blocking( so i thought)
You can use res.end and pass in a string that you want to be sent to the client:
res.end('It worked!');
Alternatively, you could render a view and then end the response:
res.render('blah.jade');
res.end();
All that said, redirecting the client is actually the best practice. It makes it so that when they hit the back button in their browser, they can move back seamlessly without getting any "POST required" popups or the like. This is the POST/redirect pattern and you can read more about it at http://en.wikipedia.org/wiki/Post/Redirect/Get.
For future reference, you can also do:
res.redirect('back');
Basically this just redirects the browser back to the screen the request came from, in other words "refreshing" it. It's hacky and I wish there was a better way, but it works.
While you can use the underlying end method borrowed from Node's http module, Express.js has its own send method that calls end when appropriate:
/**
* Send a response.
*
* Examples:
*
* res.send(new Buffer('wahoo'));
* res.send({ some: 'json' });
* res.send('<p>some html</p>');
* res.send(404, 'Sorry, cant find that');
* res.send(404);
*
* #param {Mixed} body or status
* #param {Mixed} body
* #return {ServerResponse}
* #api public
*/
res.send = function(body){
.
.
.
// respond
this.end(head ? null : body);
return this;
};
Use --> res.status(204).send(); inside the post request
if(err) {
console.log(err);
} else {
res.status(204).send();
}
If you could modify your client side code to make the post request via AJAX, you could simply use res.end().
The problem here is that when the browser makes a POST request (not via AJAX), it no longer cares about the current page. It is expecting a new page, so it will load a new page. This is purely with the browser, and I do not believe there is currently a way for you to work around it.
Overall, you should just use an AJAX POST request if you can.
The client browser is waiting for a response. So why not give it one with something like res.send('<p>Thank you</p>'); or a nice rendered view?
The reason res.end() sends the client to a blank page is that you aren't giving the client anything to display.
The best way to end the express routing without routing to new page or what ever the mess express want you not to stay on the current page although you have your own reason is to use window.stop, for example a form, you use javascript to handle the submission, the timeout should be enough to ensure the data is send as POST method.
document.myform.mysubmit.click()
setTimeout(function(){
window.stop()
}, 3000);

Resources