How to handle Node.js http server timeout event? - node.js

I have a HTTP server that will always result in HTTP timeout, e.g.
const server = http.createServer((req, res) => {
setTimeout(() => {
res.writeHead(200);
res.write('OK');
res.end();
}, 2000);
});
server.setTimeout(1000);
server.on('timeout', (socket) => {
// How to produce a custom HTTP response here?
});
HTTP server "timeout" event is emitted with socket reference. How do I use socket to encode HTTP response?
I know that I can stitch the response myself at a low-level, e.g.
server.on('timeout', (socket) => {
socket.write([
'HTTP/1.1 408 Request Timeout',
'Connection: close'
].join('\n') + '\n\n');
socket.end();
});
But is there a way to use the HTTP response interface, i.e. writeHead/ write/ end?

You could use the setTimeout function on the response object. Consider this simple example:
const http = require('http');
const port = 3000;
const requestHandler = (req, res) => {
res.setTimeout(Math.random() * 2500, () => {
res.writeHead(408);
res.end();
});
setTimeout(() => {
if (res.headersSent) {
return;
}
res.writeHead(200);
res.write('OK');
res.end();
}, 2000);
};
const server = http.createServer(requestHandler);
server.listen(port, (err) => {
if (err) {
return console.log('an error happened', err)
}
console.log(`server is listening on ${port}`)
});
If you call localhost:3000 in your web browser you'll now either see 200 OK or a 408 error. Note that you'll need to handle already sent headers if the random timeout was less than 2000 ms.

Related

node js http createServer socket

The doubt with with code is two things:
When i send request through a browser, i dont get a console log message as "connected" but if i use http.get() or http.request() , it works fine
2)The "connect" event receives a callback with req,clientSocke,head ! now where can i see the server socket ?
const http=require("http")
const server=http.createServer()
server.on("connect",(req,c_socket,head)=>{
console.log("connected")
})
server.listen(5000,()=>{console.log("server up)})
when you access the server via browser, the method is using GET not CONNECT. That's why console.log does not show.
if you want console.log to show when accessing from the browser, you can use request event.
this is an explanation from node.js docs.
'connect' event is emitted each time a server responds to a request
with a CONNECT method. If this event is not being listened for,
clients receiving a CONNECT method will have their connections closed.
node.js docs
you can make a socket server with a net package with createSever method.
this is an example of how to make a simple request to the socket server.
const http = require('http');
const net = require('net');
const { URL } = require('url');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('hello world');
});
server.on('connect', (req, clientSocket, head) => {
console.log('connected');
// Connect to an origin server
const { port, hostname } = new URL(`http://${req.url}`);
const serverSocket = net.connect(port || 80, hostname, () => {
clientSocket.write(
'HTTP/1.1 200 Connection Established\r\n' +
'Proxy-agent: Node.js-Proxy\r\n' +
'\r\n'
);
serverSocket.write(head);
serverSocket.pipe(clientSocket);
clientSocket.pipe(serverSocket);
});
});
server.listen(5000, () => {
console.log('server up');
});
// Make a request to a tunneling server
const req = http
.request({
port: 5000,
host: 'localhost',
method: 'CONNECT',
path: 'www.google.com:80',
})
.end();
req.on('connect', (res, socket, head) => {
console.log('got connected!');
// Make a request over an HTTP tunnel
socket.write(
'GET / HTTP/1.1\r\n' +
'Host: www.google.com:80\r\n' +
'Connection: close\r\n' +
'\r\n'
);
socket.on('data', (chunk) => {
console.log(chunk.toString());
});
socket.on('end', () => {
console.log('end');
});
});

Socket.io multiple response instead of one

I'm facing a problem with socket.io and node js.
Context
I have two servers, one of them is processing heavy jobs and the other is responding to the clients.
The main case is the following one :
The client request data
The "mid server" looks if I have this data in the database. If I haven't, itsend a request to the second server
The second server performs the research.
Once its done, the second server push de data to the "mid server"
The mid server finally push the data to the client (and persists it for future client requests)
Here's the sample code
Client
<script type="text/javascript"/>
var socket = io('https://localhost:9091', {'forceNew': true);
// send a request to the mid server
socket.emit('request', data);
socket.on('response', async (response) => {
// when the mid server responds, the response is printed
$('#container').append(response);
});
</script>
Mid server
const app = require('express')();
const http = require('http').createServer(app);
const io = require('socket.io')(http);
// in order to use this server as a Socket.io client
const secondServer = require('socket.io-client').connect('http://localhost:9092');
app.set('view engine', 'ejs');
app.get('/', (req, res) => {
res.render('index', {})
});
io.on('connection', async (socket) => {
console.log('User connected');
// On client request
socket.on('request', async (data) => {
console.log('Requesting from ' + socket.id);
// The same request is transmited to the second server
secondServer.emit('request', data);
});
// Once the second server has finished his job
secondServer.on('response', async (data) => {
console.log('Responding for ' + socket.id);
// I send the data back to the client
socket.emit('response', data);
});
socket.on('disconnect', () => {
socket.disconnect();
});
});
// port is 9091
http.listen(port, () => {
console.log('Server listening on port ' + port);
});
Second server
const io = require("socket.io").listen(9092);
io.on("connection", function (socket) {
socket.on('request', async () => {
// await in order to wait the heavyJob to be done before sending the response
var data = await heavyJob()
// Send back the data to the mid server
socket.emit('response', data);
});
});
Problem
The problem I'm facing is, if I refresh the client page, the mid server will send twice the data, once to the old socket and the once for the new one as so :
I have also tried to respond to the client with socket.emit('response', data) on mid server side and socket.on('response', (data) => {}) on client side instead of using callback function. It doesn't change anything.
Do I misunderstanding something ?
Thanks for your help
Edit
It doesn't only happen when the client is refreshing his page. It happens when two different clients send a request at the same time. The server is responding four times, two times for each client.
You are right Nico, I didn't recognized callback can't be reached.
It was my mistake.
According to your edited code, you can pull out "secondServer.on('response'.." from "io.on('connection'"'s callback.
You can try below and I hope this would be helpful.
Mid Server
io.on('connection', async (socket) => {
console.log('User connected');
// On client request
socket.on('request', async (data) => {
console.log('Requesting from ' + socket.id);
// The same request is transmited to the second server
// give data and socket.id to secondServer.
secondServer.emit('request', {data:data, id:socket.id});
});
// Once the second server has finished his job
socket.on('disconnect', () => {
socket.disconnect();
});
});
secondServer.on('response', async (reply) => {
const {id, data} = reply;
console.log('Responding for ' + id);
// I send the data back to the client
io.to(id).emit('response', data);
});
Second Server
const io = require("socket.io").listen(9092);
io.on("connection", function (socket) {
socket.on('request', async (req) => {
// await in order to wait the heavyJob to be done before sending the response
const {id} = req;
var data = await heavyJob();
const reply = { id, data };
// Send back the data to the mid server
socket.emit('response', reply);
});
});
I think you need pull out "secondServer.on('response'.." code from "socket.on('request',..." callback.
io.on('connection', async (socket) => {
console.log('User connected');
// On client request
socket.on('request', async (data, callback) => {
console.log('Requesting from ' + socket.id);
// The same request is transmited to the second server
secondServer.emit('request', data);
});
secondServer.on('response', async (data) => {
console.log('Responding for ' + socket.id);
callback(data.images);
});
});

Want to write capture and re-transmit http/https request to Browser?

I want to write a simple Node Js application which will capture and re-transmit http/https request to Browser?
I have written the below code, but it works only for http request.
var server = http.createServer(function (req,res) {
console.log("start request:", req.url);
var option = url.parse(req.url);
option.headers = req.headers;
var proxyrequest = http.request(option, function (proxyresponce) {
proxyresponce.on('data', function (chunk) {
console.log("proxy responce length" ,chunk.length);
res.write(chunk,'binary');
});
proxyresponce.on('end',function () {
console.log("proxy responce ended");
res.end();
});
res.writeHead(proxyresponce.statusCode, proxyresponce.headers);
});
});

HttpOnly cookie can be accessed in a node client?

I'm new to node and going through some tutorials. I've got a simple node server running this code:
// SERVER CODE
const http = require('http');
const Cookies = require('cookies');
const port = 3000;
const requestHandler = (request, response) => {
cookies = new Cookies(request, response);
cookies.set("foo", "bar", { httpOnly: true });
response.end('Hello Node.js Server!');
}
const server = http.createServer(requestHandler);
server.listen(port, (err) => {
if (err) {
return console.log('something bad happened', err);
}
console.log(`server is listening on ${port}`);
})
And I have another .js file that tries to access this server:
//CLIENT CODE
const http = require('http')
http.get('http://machine_name:3000', (
console.log(res.headers['set-cookie']);
});
From my understanding, httponly cookies should be unable to be available by client Javascript. When I run the client code though, I get:
[ 'foo=bar; path=/; httponly' ]
Is this right? Am I not setting it up correctly? I feel like this is an error since the httponly property means I shouldn't be able to access it via Javascript.
What you are doing is doing it in the right way and this you can try with your browser.
Si tienes un archivo index con el siguiente contenido:
// index.js file
const http = require('http');
const Cookies = require('cookies');
const port = 3000;
const requestHandler = (request, response) => {
cookies = new Cookies(request, response);
cookies.set("foo", "bar", { httpOnly: true });
response.end('Hello Node.js Server!');
}
const server = http.createServer(requestHandler);
server.listen(port, (err) => {
if (err) {
return console.log('something bad happened', err);
}
console.log(`server is listening on ${port}`);
})
When you execute the command
node index.js
And you open your browser, open the console and execute the following
console.log( document.cookie ) // this not return your cookies
But if you have { httpOnly: false } you can get the following:
"other-cookies; foo=bar"
This is because JavaScript uses cookies more in the browser itself than in the console, if you have the httpOnly flag activated you can be 100% sure that no JS script can use it.
Read more about cookies

Nodejs - SPDY push on request error

I am having trouble launching my Node app. I get "TypeError: Cannot call method 'push' of undefined" error.
Here is my code:
spdy.createServer(credentials, app).listen(app.get('port'), function(req, res) {
res.push('public/js/bootstrap.min.js', {'content-type': 'application/javascript'}, function(err, stream) {
stream.end('alert("hello from push stream!")');
});
res.push('public/js/jquery.min.js', {'content-type': 'application/javascript'}, function(err, stream) {
stream.end();
});
res.push('public/css/bootstrap.min.css', {'content-type': 'text/css'}, function(err, stream) {
stream.end();
});
// write main response body and terminate stream
res.end('Hello World!');
console.log('Express HTTPS SPDY server listening on port ' + app.get('port'));
} );
I am running SDPY version 1.19.2 and NodeJS version 0.10.25.
Based on your comment, you are serving with HTTP/1.1. You need to be serving with HTTP2/SPDY for push to work.
Try this:
// set the root path of Express server
app.use(express.static(__dirname+'/public');
app.use(function(req, res) {
// your res.push code is here.
var stream = res.push('/js/bootstrap.min.js', {'content-type': 'application/javascript'});
stream.on('acknowledge', function() {
console.log('stream ACK');
});
stream.on('error', function() {
console.log('stream ERR');
});
stream.end('alert("stream SUCCESSFUL");');
res.end('<script src="/js/bootstrap.min.js"></script>');
});
spdy.createServer(credentials, app).listen(app.get('port'));
The callback function passed to listen() function takes no arguments. see line 49, file stream-test.js

Resources