Disable bodyparser for file uploads - Nodejs - javascript

This question is very similar to How to disable Express BodyParser for file uploads (Node.js). The answer they have provided is for Express3 and I have tried the solution with the updated Express 4 and it does not seem to work.
I'm using Node.js + Express to build a web application. I am using another library,BodyParser,to parse post parameters. However, I would like to have more granular access to multipart form-data POSTS as they come - I need to pipe the input stream to another server, and want to avoid downloading the whole file first.
All file uploads are parsed automatically and uploaded and available using "request.files" before they ever get to any of my functions.
Is there a way for me to disable the BodyParser for multipart formdata posts without disabling it for everything else?
This is my app.js file. In here I am defining an authentication route which shouldn't except any files just a token (POST parameter). I am also defining another route called upload. This route accepts a file and also POST parametes (form-data). This route only gets called if the authentication route allows it. So in the authetnication route I don't want form-data to be allowed, but in the upload route I do. So when I get a request to uplaod something it will go through the auth route and then the upload route. Due to this I need to allow the auth route to allow files (form-data) which I do not want. So I want bodyparser to work in the auth route while I use mutler (another library) in my upload path to parse my upload files. In my real application though of course I have many more routes and would like to code it as cleanly as I can with the least amount of redundancy.
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
extended: true
}));
var route_auth = require('./routes/auth');
app.use('/api/post/*', route_auth);
var route_upload = require('./routes/post/upload');
app.use('/api/post/upload', route_upload );
app.listen(3000, function() {
console.log('Server listening on port 3000!')
});
My auth route looks something like this:
router.post("/", function(req, res, next) {
if(everythingiscool){
return next()
}
next(err);
});
My upload route looks like this:
var express = require('express');
var router = express.Router();
var multer = require('multer')
var upload = multer({ dest: 'uploads/' });
router.post("/", upload.single('avatar'), function(req, res, next) {
//work with req.file
});

Wrap the bodyParse middleware in a function that checks if the request body's Content-Type is multipart or not:
var isMultipart = /^multipart\//i;
var bodyParser = require('body-parser');
var urlencodedMiddleware = bodyParser.urlencoded({ extended: true });
app.use(function (req, res, next) {
var type = req.get('Content-Type');
if (isMultipart.test(type)) return next();
return urlencodedMiddleware(req, res, next);
});

Instead of disabling, why not enable the middleware on the routes/routers where you need it?
For individual routes, you can just add it as another argument before your actual route handler, for example:
app.post('/upload', bodyParser, (req, res) => {
// route logic here
});

Related

Correct format for Node architecture (BASIC)

Introduction
I have built some back end functionality in Node (First time using Node). Problem is that the whole thing was built in one page (index.js) so now im following a few basic tutorials and setting out express router middleware and now trying to follow a modular MVC approach,
This code is simple but brakes when I separate into two pages Server.js and config.js. I know its a simple problem but i cant spot it. can someone help spot the problem and maybe improve the structure ?
Problem
I go to http://localhost:8080/about or a different route and I get
Cannot GET /about
rather than the correct print out.
back-end/server.js
var express = require('express');
var app = express();
var port = process.env.PORT || 8080;
// get an instance of router
var router = express.Router();
// START THE SERVER
// ==============================================
app.listen(port);
console.log('Server has started!! ' + port);
back-end/config.js
router.use(function(req, res, next) {
console.log(req.method, req.url);
next();
});
router.get('/', function(req, res) {
res.send('im the home page!');
});
// sample route with a route the way we're used to seeing it
router.get('/sample', function(req, res) {
res.send('this is a sample!');
});
router.get('/about', function(req, res) {
res.send('im the about page!');
});
app.route('/login')
.get(function(req, res) {
res.send('this is the login form');
})
.post(function(req, res) {
console.log('processing'); // shows on console when post is made
res.send('processing the login form!'); // output on postman
});
app.use('/', router);
As #SLaks said in his comment, you need to import (require) your backend/config.js file. But it's not as simple as that...
In node, variables are scoped to the file in which they appear, so if you simply add require('./config') to your server.js file, that's not going to work either, because the router variable in config.js is local to that file - it's not going to know about the router variable in server.js.
The solution to this is to have the config.js file export a function which the server.js file can use to configure stuff. For example
config.js
module.exports = function(router) {
// set up your router here with router.use, etc.
};
server.js
var configure = require('./config');
// after you set up your express router...
configure(router);
// now start listening

Multiple level of routing using Express.js with Node.js

I'm new to javascript. I'm trying to make a RESTfull API using Node.js and Express.js
My directory structure is as follows
/server.js
/api/api.js
/api/location/location.js
I want to make the API modular. I want that all the requests (get/post/delete/push) beginning with /api/* to be handled by api.js and whatever routing be required, api.js should route it to proper module.
For example, if someone requests GET /api/location/abc/xyz then api.js will transfer control to location.js which will then transfer to abc.js which will finally transfer to xyz.js stored in directory /api/location/abc/xyz/xyz.js
How can I achieve this?
Code so far:
/server.js
var express = require('express');
var app = express();
var api = require('./api/api.js');
var location = require('./api/location/location.js');
//app.use('/api/location', location); //This works, but I want api.js to handle sub-routes!
app.use('/api', api);
app.get('/', function(req, res){
res.end('successful get/');
});
app.listen(12345);
/api/api.js
module.exports = function(req, res, next) {
res.end('successful get /api');
next();
};
//Add code to handle GET /api/location
/api/location/location.js
module.exports = function(req, res, next){
res.end('from location!');
next();
}
You would use express.Router([options]).
And write it that way:
/api/api.js
var router = require('express').Router();
router.get('/location', require('./api/location') );
module.exports = router;
/api/api/location.js
module.exports = function(req, res, next){
res.end('from location!');
}
And don't call next(); if you ended the response. You only call next() in your callback if you don't handle the response.
I don't know how complex your REST api will be later. But try to to keep the routing in a small number of file. Having a callback for the routing in an own file like /api/api/location.js is most likely not the best idea.

Express request body for post is undefined

I have the following setup in my app.js:
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.json());
var router = express.Router();
require('./routes/index')(router);
app.use(router);
In my routes/index.js I have all the routes defined:
module.exports = function (router) {
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Home' });
});
router.post('/', function(req, res, next) {
console.log(req.body);
});
}
Then in my app entry point bin/server.js:
var app = require('../app');
var debug = require('debug')('NodeJSDemo:server');
var http = require('http');
var port = 3000;
app.set('port', port);
var server = http.createServer(app);
server.listen(port);
When I make a POST call on http://localhost:3000/ with a request body, in the console log console log request body is undefined.
Is there anything wrong with my setup? From this post Express.js req.body undefined it seems as long as I call
app.use(bodyParser.json())
before loading routes, it should be fine but seems like it does not.
The problem arises from what type of resource you are sending on your POST request.
Your bodyParser.json() is ONLY parsing json format. Or in other words if you simply POST a simple form that in most cases defaults to application/x-www-form-urlencoded you will not get the body object.
As it is stated in the documentation:
Returns middleware that only parses json and only looks at requests
where the Content-Type header matches the type option.
and
type - The type option is used to determine what media type the middleware
will parse.
Defaults to application/json.
The solution would be to implement and cather from other scenarios so:
application/x-www-form-urlencoded
app.use(bodyParser.urlencoded())
multipart/form-data
Express does not parse multipart bodies as stated in the documentation:
This does not handle multipart bodies, due to their complex and
typically large nature. For multipart bodies, you may be interested in
the following modules:
busboy and connect-busboy
multiparty and connect-multiparty
formidable
multer
For Express versions: +4.17.0
You could not include the bodyParser dependency. And use the express built-in methods as:
express.json()
express.text()
express.urlencoded()
They are built based on the bodyParser module so instead calling bodyParser.json(). You would do express.json() and achieve the same results.
Source:
https://expressjs.com/en/resources/middleware/body-parser.html#bodyparserurlencodedoptions

Migrating away from bodyParser() in Express app with busboy?

Being a newbie in Nodejs, I jumped right into writing a simple app without really reading up on good security practices. I just found out that using bodyParser() for all routes is actually a bad thing because it allows for DOS attack using multipart files.
A recommended fix is to only load specific modules depending on the route. ie, for multipart fileupload, use multipart. For regular POST without file uploads (ie, text form submission), use express.json(), express.urlencoded().
Or another option is to use busboy with connect-busboy. But the thing I'm confused on is how I can specify which route should handle multipart data and which should not? Otherwise, wouldn't I have the same problem as with bodyParser?
Furthermore, busboy docs says it does not handle GET:
If you find that req.busboy is not defined in your code when you expect it to be, check that the following conditions are met. If they are not, req.busboy won't be defined:
1. The request method is not GET or HEAD
So, I'm even more confused how I would parse params in a GET. I think bodyParser does this for me so I could access data with req.params.
For example, how would I migrate away from bodyParser() to busboy/connect-busboy with this simple app:
var express = require('express');
var app = express();
var http = require('http').Server(app);
var bodyParser = require('body-parser');
app.use(bodyParser.json());
var busboy = require('connect-busboy');
app.use(busboy());
// How to use busboy to prevent multipart files here?
app.post("/form_data_no_fileupload", function(req, res) {
var somedata = req.body.somedata;
});
// Use busboy to handle both regular form data + fileuploads
app.post("/form_data_AND_fileupload", function(req, res) {
});
// What would handle GET without bodyparser?
app.get("/get_something", function(req, res) {
var params = req.params;
});
http.listen(3000, function() {});
[How] I can specify which route should handle multipart data and which should not?
All of Express' routing methods allow for providing middleware specific to the route. This includes Router methods.
app.METHOD(path, callback [, callback ...])
Depending on the body expected for an individual route, you can use different modules to handle each of them (rather than applying them to the entire application with app.use()).
var express = require('express');
var app = express();
var http = require('http').Server(app);
var bodyParser = require('body-parser');
var busboy = require('connect-busboy');
app.post("/form_data_no_fileupload",
bodyParser.urlencoded(),
function(req, res, next) {
// check that the request's body was as expected
if (!req.body) return next('route'); // or next(new Error('...'));
// ...
});
app.post("/form_data_AND_fileupload",
busboy({
limits: {
fileSize: 10 * 1024 * 1024
}
}),
function(req, res, next) {
// check that the request's body was as expected
if (!req.busboy) return next('route'); // or next(new Error('...'));
// ...
});
// ...
Furthermore, busboy docs says it does not handle GET.
So, I'm even more confused how I would parse params in a GET.
Busboy and BodyParser are designed for reading in and parsing the request's body, which GET and HEAD requests aren't expected to have.
For such requests, parameters can only be passed within the query-string within the URL, which Express parses itself. They're available via req.query.
app.get('/get_something', function () {
console.log(req.originalUrl);
// "/get_something?id=1
console.log(req.query);
// { id: "1" }
});
req.params represents any placeholders matched in the path by the route. These are available for any route, regardless of the method.
app.get('/thing/:id', function (req, res) {
console.log(req.originalUrl);
// "/thing/2"
console.log(req.params);
// { id: "2" }
});

How do I serve a static file using Node Express?

I was having trouble settings up a very basic static file sever using express with Node.js. I set up a simple server.js but cannot see any files when I load the URL localhost:9000 in my web browser.
All I see is a page saying: Cannot get /
var express = require('express');
var app = express();
app.use(function(req, res, next) {
next();
});
app.use(express.static(__dirname));
app.listen(9000);
Simply you're exposing nothing. Do you have, for example, an index.html file? Try this:
app.get("/", function(req, res) {
res.sendfile("index.html");
});
Did you go through the NodeSchool workshoppers? They have step-by-step examples that cover this and more.
Here is the workshop for Express.
Here is my solution for the 'static' question in the workshop.
var express = require('express')
var app = express()
app.use(express.static(process.argv[3]||path.join(__dirname, 'public')));
app.use(require('stylus').middleware(__dirname + '/public'));
app.post('/form', function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' })
res.end()
})
app.listen(process.argv[2])
Express does not create a directory listing. Even thought it does not list the files in the directory, it does serve them up when hitting them in the web browser.
Point the browser to the actual file:
http://localhost:9000/public/test.html
Originally I found this confusing because I had expected the express server to list directories; when seeing "something"... a page that said "Cannot get /" I assumed that page would normally have a list of files.

Categories

Resources