Is it possible using Node.js and express to drop a request for certain route? I.E. not return a http status or any headers? I'd like to just close the connection.
app.get('/drop', function(req, res) {
//how to drop the request here
});
To close a connection without returning anything, you can either end() or destroy() the underlying socket.
app.get('/drop', function(req, res) {
req.socket.end();
});
I don't think there's any way to drop the connection at your end but keep the client waiting until it times out (i.e. without sending a FIN). You'd perhaps have to interact with your firewall in some way.
Yes you can.
All you need to do is call the res.end method optionally passing in the status code.
Use one of the following methods:
res.end();
res.status(404).end();
If you wanted to also set the headers, then you'd use the res.set method.
See below
res.set('Content-Type', 'text/plain');
res.set({
'Content-Type': 'text/plain',
'Content-Length': '123',
'ETag': '12345'
})
For details have a look here
http://expressjs.com/api.html
You could do this wherever you want to close the connection:
res.end()
Related
I am trying to setup a very simple nodeJS HTTP server. When I call it from the browser, like this http://localhost:8081, it works fine, but when I call is using a JS fetch() method, I get a 404 error:
GET http://localhost/:8081?q=hi
JS:
fetch(":8081/?q=hi")
NODE JS:
const requestListener = function (req, res) {
res.writeHead(200);
res.end('Hello, World!');
}
const server = http.createServer(requestListener);
server.listen(8081);
Every thing is fine, you just need to enable cors that's it, use the below code
const http = require('http')
const requestListener = function (req, res) {
const headers = {
'Access-Control-Allow-Origin': '*', /* #dev First, read about security */
'Access-Control-Allow-Methods': 'OPTIONS, POST, GET',
'Access-Control-Max-Age': 2592000, // 30 days
/** add other headers as per requirement */
};
res.writeHead(200, headers);
res.end(JSON.stringify({"key":"value"}));
}
const server = http.createServer(requestListener);
server.listen(8081);
If you are running both frontend and backend code on the same server then you don’t have to use complete url while if you are running fronted and backed on different server you need to enable cors and use complete url.
When you're calling your local server through JS fetch, you don't need to add the port number you can call it like below:
fetch('/?q=hi')
the URL handed to fetch function looks wronge, it would work if you adjust it to:
fetch('http://localhost:8081/?q=hi');
// or
fetch('/?q=hi');
it should work just fine,
and ensure that you enable the cors if you need to works from any domain
I am writing a bare minimal node.js server to understand how it works. From what I can tell this line:
res.writeHead(200);
does nothing. If I remove it I get the exact same behavior from the browser. Does it have any purpose? Is it OK to remove it?
// https://nodejs.dev/learn/the-nodejs-http-module
const http = require('http');
const server = http.createServer(handler);
server.listen(3000, () => {
console.log('node: http server: listening on port: ' + 3000);
});
function handler(request, response) {
res.writeHead(200);
res.end('hello world\n');
}
Is it some how related to http headers?
The default http status is 200, so you do not have to tell the response object that the status is 200. If you don't set it, the response will automatically be 200. You can remove res.writeHead(200); and similarly, you don't need the express version of that which would be res.status(200).
The other thing that res.writeHeader(200) does is cause the headers to be written out in the response stream at that point. You also don't need to call that yourself because when you do res.send(...), the headers will automatically be sent first (if they haven't already been sent). In fact, the res.headersSent property keeps track of whether the headers have been sent yet. If not, they are sent as soon as you call any method that starts sending the body (like res.send() or res.write(), etc...).
Is it OK to remove it?
Yes, in this context it is OK to remove it.
Is there any way to tamper with the data that socket.io sends just before it is sent/received? I was thinking about something like an express middleware.
So that I could encode data after the normal .emit() method is called and before socket.on(...) is called.
In express I would imagine it to look somewhat like this to BISON decode all incoming request:
app.use(function(req, res, next) {
req.body = BISON.decode(req.body);
next();
});
Now how could that be done with socket.io in a way that requests being sent also get encoded automatically?
I know that socket.io supports middlewares in a similar form to express, but that is only for the actual http request that socket.io sends to create the websocket connection...
io.use(function(socket, next) {
//...
next();
});
so I doubt that this would be of any help here..
You can intercept (and change) data by listening for packet events, and similarly use the flush event to intercept outgoing messages:
io.use(function(socket, next) {
socket.conn.on('packet', function(packet) {
...change `packet.data` here...
});
socket.conn.on('flush', function(packets) { // array of packets
...
});
next();
});
But to be honest, I'm having a hard time finding documentation on how packet.data is encoded, so I can't provide a full example.
EDIT: socket.io-parser has decodeString() which is used to parse the payload. Sadly, it's not exported (and the methods that are exported are all async, which doesn't combine well with event handlers).
We have a Node/Restify app and I'm having a problem with this route (some code has been omitted, so please ignore missing identifiers):
server.post('/report', requireAuth, function (req, res, next) {
generateReport(err, result, extension, contentType) {
// Filename for the report
var filename = 'Report_' + moment().format('YYYY-MM-DD_HH:mm:ss')
// Output the result directly with a lower-level APIs
res.writeHead(200, {
'Content-Length': Buffer.byteLength(result),
'Content-Type': contentType,
'Content-Disposition': 'attachment;filename='+filename+'.'+extension
})
res.write(result, 'utf8')
res.end()
console.log('ended')
return next()
}
})
The problem is that, after sending the output, the connection with the client is not closed, even if I call res.end()! (res is just a wrapper around the standard HTTP ServerResponse module).Commenting out return next() doesn't make any difference.
I can see on the console 'ended' and I know the content is sent to the client because if I force the termination of the connection (by simply terminating the Node process), the client has all the output.
What am I doing wrong?
EDIT
Removing the Content-Length header, instead, makes it work. Why is that? (The advice to use that header is part of the documentation)
EDIT2
The value of Buffer.byteLength(result) is 4478 bytes, but the data downloaded by the client (Postman) is 4110, and that's likely why the connection is not being closed (the client is expecting to receive more data). How is that possible?
I am trying to pipe images from an Amazon S3 server through my node server while adding a custom header to the response.
Right now, however, the server will respond with a plain "Document" that will download to my computer with no file extension declared. The "Document" still contains the desired image data, but how can I make it clear that this is a PNG that can be viewed in my browser?
Here's my current code:
app.get('/skin', function (req, res) {
res.writeHead(200, {'Content-Type': 'image/png', 'access-control-allow-origin': '*'});
http.get("http://s3.amazonaws.com/MinecraftSkins/clone1018.png").pipe(res);
});
You might want to use http.request in order to make nice proxying and resource loading with duplicating headers.
Here is example in express that will listen on port 8080, and will make request to specific server with actually url that you request from /skin/* route:
var http = require('http'),
express = require('express'),
app = express();
app.get('/skin/*', function(req, res, next) {
var request = http.request({
hostname: 's3.amazonaws.com',
port: 80,
path: '/' + req.params[0],
method: req.method
}, function(response) {
if (response.statusCode == 200) {
res.writeHead(response.statusCode, response.headers);
response.pipe(res);
} else {
res.writeHead(response.statusCode);
res.end();
}
});
request.on('error', function(e) {
console.log('something went wrong');
console.log(e);
})
request.end();
});
app.listen(8080);
In order to test it out, run it on your machine, and then go to: http://localhost:8080/skin/nyc1940/qn01_GEO.png
It will load that image proxying from Amazon, and returning its headers as well. You might customize headers as well, in order to prevent XML being sent from S3 (when file does not exist).
You dont need to set any headers as they are proxied from s3.amazon and it does reliably set right headers for you.
Nor access-control-allow-origin as you will need it only in case with AJAX request to resource from another domain name. But anyway feel free to modify response.headers before sending out. It is simple object (console.log it for tests).