ExpressJS: How to know when a request has finished? - javascript

In an ExpressJS set up on top of NodeJS, I have a bit of code like this:
app.get('/keys/readresults/:keyname', basic_auth, function(req,res){
res.writeHead(200, {'content-type': 'text/json'});
setInterval(
go_to_database_and_get('stuff', function (database_replies) {
res.write(database_replies)
})
,5000);
});
The code is wrote like that for simplicity (if anyone wants the real code I'm happy to post it in some pastebin).
What happens when I curl -u username:password http://localhost:4000/keys/readresults/key is exactly what I wanted to happen: I get a 200 status header, it checks the database for any results I want and writes the response back to me, then waits 5 seconds and searches for new results in the database and writes the response again, and so on every interval of 5 seconds.
The problem is that when I exit curl, the loop keeps on going forever. How do I tell express or nodejs that it's supposed to end that loop (with clearInterval I guess) as soon as the request has ended ?

req.on("close")
So simply
app.get('/keys/readresults/:keyname', basic_auth, function(req,res){
res.writeHead(200, {'content-type': 'text/json'});
var no = setInterval(
go_to_database_and_get('stuff', function (database_replies) {
res.write(database_replies)
});
,5000);
req.on("close", function() {
clearInterval(no);
});
});

req.on('close', ...) no longer works in Express 4. Use the on-finished middleware.

With express 4.X it is req.on("end", () => {}), it is better to add this as a express middleware.
Yeah but on-finished npm package works too.

Related

Is there a way to run this http response callback in an asynchronous way?

I'm building a basic http server (using only inside lan, to do some things) and for that im using node js. I've started my server and i wrote a basic callback function to respond to http requests. However, i wanted to see what would happen if the function i'm running took some time to conclude (like a db query, for example). So i've wrote this:
const http = require("http");
const router = require("../routes/router").router;
const config = require("../config/serverconf.json");
class HttpServer {
constructor() {
this.httpServer = http.createServer();
this.httpServer.on("request", (req,res)=>{return new Promise((resolve)=>{
setTimeout(()=>{
res.writeHead(200, {"Content-Type":"text/plain"});
res.write("Hello World!");
res.end();
},2000);
console.log("resolved");
console.log("--------")
resolve("ok");
})});
this.httpServer.listen(config.port, config.host);
}
}
(It was a little more complex, i tried to put it all in the same snippet to better show my problem).
From my understanding, when a request arrives, the callback function creates a new promise, that runs the function in the promise constructor. This function schedules the timeout callback, logs some stuff, then resolves the function. However, it seems that despite the function have already finished, when another request arrives, it waits for the timeout callback function to finish before scheduling the next request's timeout callback. (For example, if i were to get two requests "at the same time" one would take 2 seconds to finish, and the other would take 4). Am i thinking about it the wrong way? If so, how could i achieve something like title's idea. Thanks in advance!
Ok, so apparently, there was something wrong with my browser (using Google Chrome, but tried on MS Edge too). I changed my code a little bit and tried again. This time the response times were very inconsistent, but it seemed like it was kinda working. Took the advise from #Bergi and tried making the requests with curl and sure enough, it worked just fine (without the chunked encoding). Heres the new code:
HttpServer.js:
const http = require("http");
const router = require("../routes/router").router;
const config = require("../config/serverconf.json");
class HttpServer {
constructor() {
this.httpServer = http.createServer();
this.httpServer.on("request", async (request, response)=>{
let responseParams = await router.routeCall(request);
response.writeHead(responseParams.responseCode, responseParams.headers);
response.write(responseParams.body);
response.end();
});
this.httpServer.listen(config.port, config.host);
}
}
router.js:
class router{
static routeCall(url){
switch(url){
default:
return new Promise((resolve)=>{
setTimeout(()=>{
resolve({
"responseCode":200,
"body":"Message Resolved! Hello! :D",
"headers":{"Content-Type":"text/plain"}
});
}, 2000);
});
}
}
}
I would still like to know what is wrong with the first aproach, as i really dont know why it fails (at least on my end). Thanks again #Bergi :D

Why does settimeout break Expressjs

I have the following code in express.js
// POST api/posts/:id
exports.post = function(req, res){
req.body[0].id = posts.length + 1;
posts.push(req.body[0]);
console.log(posts);
fs.writeFileSync("json/posts.json", JSON.stringify(posts));
setTimeout(function(){
res.set.apply(res, utils.contentType);
res.json(req.body[0]);
}, utils.randomNumberBetween(1000, 3000));
};
When I post a simple json object I receive the following error.
org.apache.http.NoHttpResponseException: localhost:9000 failed to respond
If I remove the settimeout everything works as expected. I have used settimeout in other places like so:
// GET api/posts
exports.get = function(req, res){
setTimeout(function(){
res.set.apply(res, utils.contentType);
res.json(posts);
}, utils.randomNumberBetween(1000, 3000));
};
So I'm not understanding why it would break when posting. Any thoughts??
This is because the application making the request expects a response from express within a certain amount of time, say 5 seconds. If it does not receive anything back it thinks something went wrong. One thing you can do to resolve this is change the amount of time your "sending/requesting" application waits/listens for a response.

Node JS HTTP Server request.on('data') event failure

I am working on a NodeACS app in which I have to send xml as request from Java HTTP client and to receive response after some manipulation. The Java HTTP Client is working fine so far but the issue is with Node JS file. The req.on('data'...) event is not firing in my case.
Following is the code of my JS file:
function index(req, res) {
console.log(req.headers); //Its getting printed on console
req.on('data', function (data) {
console.log("Inside 1"); //Not printed on console
....REST OF THE CODE....
});
req.on('end', function () {
res.writeHead(200);
res.end();
});
}
In the above code after getting request the index function is called and printing the output for console.log(req.headers); but as mentioned above the script is not running after that. Please help me out What am I missing in this.
For testing I have installed cURL on my system and sending POST request to server using cURL request using following command:
curl -X POST -d #output.xml http://localhost:7788/
Can you confirm you aren't consuming the body prior to this? If the body has been consumed already by another middleware like body-parser you would need to restream the body via something like connect-restreamer. If it were consumed, the data event would not be emitted.
If that checks out, check to see if the "end" event is being emitted. Could be a sign of the content-length header being set to the wrong value.

My http.createserver in node.js doesn't work?

Hello guys i just started learning node.js today and search a lot off stuff on the internet , then try to code in node.js i use these two codes to show me the same result but the last one is show the error on my browser something likes "can not find the page".So please explain to me why?
// JScript source code
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello World\n');
}).listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/');
This is working but
// Include http module.
var http = require("http");
// Create the server. Function passed as parameter is called on every request made.
// request variable holds all request parameters
// response variable allows you to do anything with response sent to the client.
http.createServer(function (request, response) {
// Attach listener on end event.
// This event is called when client sent all data and is waiting for response.
request.on("end", function () {
// Write headers to the response.
// 200 is HTTP status code (this one means success)
// Second parameter holds header fields in object
// We are sending plain text, so Content-Type should be text/plain
response.writeHead(200, {
'Content-Type': 'text/plain'
});
// Send data and end response.
response.end('Hello HTTP!');
});
}).listen(1337, "127.0.0.1");
This one is not working
Why?
The link of the last one that's not working
http://net.tutsplus.com/tutorials/javascript-ajax/node-js-for-beginners/
Thank you for all the answers, but i still don't understand about the problems.
the last one that is not working just has request.on?
request is an instance of http.IncomingMessage, which implements the stream.Readable interface.
Documentation at http://nodejs.org/api/stream.html#stream_event_end says:
Event: 'end'
This event fires when no more data will be provided.
Note that the end event will not fire unless the data is completely consumed. This can be done by switching into flowing mode, or by calling read() repeatedly until you get to the end.
var readable = getReadableStreamSomehow();
readable.on('data', function(chunk) {
console.log('got %d bytes of data', chunk.length);
})
readable.on('end', function() {
console.log('there will be no more data.');
});
So in your case, because you don't use either read() or subscribe to the data event, the end event will never fire.
Adding
request.on("data",function() {}) // a noop
within the event listener would probably make the code work.
Note that using the request object as a stream is only necessary for when the HTTP request has a body. E.g. for PUT and POST requests. Otherwise you can consider the request to have finished already, and just send out the data.
If the code your posting is taken literally from some other site, it may be that this code example was based on Node 0.8. In Node 0.10, there have been changes in how streams work.
From http://blog.nodejs.org/2012/12/20/streams2/
WARNING: If you never add a 'data' event handler, or call resume(), then it'll sit in a paused state forever and never emit 'end'.
So the code you posted would have worked on Node 0.8.x, but does not in Node 0.10.x.
The function you are applying to the HTTP server is the requestListener which supplies two arguments, request, and response, which are respectively instances of http.IncomingMessage and http.ServerResponse.
The class http.IncomingMessage inherits the end event from the underlying readable stream. The readable stream is not in flowing mode, so the end event never fires, therefore causing the response to never be written. Since the response is already writable when the request handler is run, you can just directly write the response.
var http = require('http');
http.createServer(function(req, res) {
res.writeHead(200, {
'Content-Type': 'text/plain'
});
res.end('Hello HTTP!');
}).listen();

JSONP call with server-side language as Javascript

I've been trying to use JSONP to get a JSON object from a server via a client-side call (on a different port). However, because my server is implemented in javascript using Node.js and Express, I haven't been able to find much on JSONP with Javascript on the server as most sites I found used php for server-side code.
I believe the issue is with how I set up the url with respect to the callback, which I'm a bit fuzzy on cause it's new to me.
On the server:
//Setting up server stuff
var express = require('express'),
app = express.createServer();
app.use(express.logger());
//Making a connection to the mongoDB to get the data that I want to display in the JSON object
new Db('prism',
new Server("127.0.0.1", 27017, {auto_reconnect: false}), {}).open(function(err, db) {
app.get('/getData', function(req, res) {
console.log('JSONPCALLBACK CALLED WITH RETURNDATA PASSED IN; SERVER SIDE');
if (typeof callback == 'function') {
console.log('callback is defined');
callback(returnData);
}
else {
console.log('callback is not defined');
}
}
});
And on the client:
$.ajaxSetup({ cache : false });
$.getJSON('http://127.0.0.1:1337/getData&callback=?', function(rtndata) {
console.log('SUCCESS');
console.log(rtndata);
});
embedded by the standard tags.
But I get the error:
GET http://127.0.0.1:1337/getData&callback=jQuery16108897686484269798_1311007334273?_=1311007334342 404 (Not Found)
The server is on port 1337 while the client is run through MAMP on localhost:8888. I'm not sure if its even a localhost related issue as I've been trying to get this setup running for a few days now.
I believe the issue has something to do with not writing this line, which is in php, into my server-side Javascript. Most of the JSONP examples I found had something like this. But I'm not sure.
if ($GET['callback'] != '')
$json = $GET['callback']."( $json )";
return $json;
Any help would be greatly appreciated. I apologize ahead of times for being super verbose.
Bests,
Cong
I think you have two problems. First is the 404. Completely separate from getting the client-side jQuery code to work, you need to make sure that you can issue a regular browser request (i.e. paste in that URL) and get back what you expect. I haven't used express, so it's hard for me to comment on why you'd be getting that, except to say that I don't see 1337 anywhere in your server-side code, just what appears to be the port number 27017.
The second problem is that you don't actually want to execute the callback on the server, just build the JSON response including the callback (string) prefixed to it.
So instead of this ...
if (typeof callback == 'function') {
console.log('callback is defined');
callback(returnData);
}
else {
console.log('callback is not defined');
}
try this:
if (callback) {
console.log('callback is defined');
res.write(callback + '(' + JSON.stringify(returnData) + ')');
}
else {
console.log('callback is not defined');
}
Hope this helps!
From http://api.jquery.com/jQuery.getJSON/ there is an example that includes 2 '?' in the URL.
you only have one, so try
$.getJSON('http://127.0.0.1:1337/getData?callback=?', function(rtndata) {
and see if that gets rid of your 404
then look #jimbojw suggestion for returning a proper jsonp formated responce.
Use this:
var express = require("express");
var server = express.createServer();
server.enable("jsonp callback");
server.get("/foo", function(req, res) {
// this is important - you must use Response.json()
res.json("hello");
});
jsonp with node.js express

Categories

Resources