I'm still having difficulty understanding how to add middleware to sails.js. I've heard use policies.js, create custom policies, add to local.js, etc. So could someone please show me how exactly I would add the jquery-file-upload-middleware to a sails app. Thanks in advance
2 Answers
This would have been very difficult in previous versions of Sails, because you had no control over the order in which custom middleware was included. In v0.10, it's just kinda difficult.
Note: the following will work with the beta version of Sails (v0.10.x), installable via npm install sails@beta
.
Inserting your own custom middleware into Sails is as easy as adding a customMiddleware
function to your config/express.js
file which takes app
as an argument; you can then app.use
to your heart's content. The downside with this approach is that it doesn't give you control over when your middleware is included. Notably, it's included after the body parser, which won't work for your case.
In the newest version of Sails, you can override all of the middleware loading by implementing a loadMiddleware
method in /config/express.js
. The arguments are app
, defaultMiddleware
(the set of middleware functions that Sails usually includes by default), and sails
(a reference to the global Sails object). Take a look at the default core implementation first--you'll probably want to copy the same order. So in your /config/express.js
, you'd have something like:
var upload = require('jquery-file-upload-middleware');
// configure upload middleware
upload.configure({
uploadDir: __dirname + '/public/uploads',
uploadUrl: '/uploads',
imageVersions: {
thumbnail: {
width: 80,
height: 80
}
}
});
module.exports.express = {
loadMiddleware: function(app, defaultMiddleware, sails) {
// Use the middleware in the correct order
app.use(defaultMiddleware.startRequestTimer);
app.use(defaultMiddleware.cookieParser);
app.use(defaultMiddleware.session);
// Insert upload file handler
app.use('/upload', upload.fileHandler());
app.use(defaultMiddleware.bodyParser);
app.use(defaultMiddleware.handleBodyParserError);
app.use(defaultMiddleware.methodOverride);
app.use(defaultMiddleware.poweredBy);
app.use(defaultMiddleware.router);
app.use(defaultMiddleware.www);
app.use(defaultMiddleware.favicon);
app.use(defaultMiddleware[404]);
app.use(defaultMiddleware[500]);
}
...etc...
}

- 24,870
- 4
- 74
- 92
-
I am trying to get this to work and I have started a new sails beta 0.10.0-rc8 app to try this out. However my loadMiddleware or customMiddleware functions never seem to get executed even though /config/express.js is clearly getting processed and my upload route 404s. The github link in your posts also 404s and I am having a hard time tracking down where they would be called. – Alex Muro Jun 14 '14 at 19:25
-
Updated the link, and updated the answer to reflect that it needs to be `module.exports.express`--surprised nobody pointed out the mistake earlier. Thanks for the heads-up! – sgress454 Jun 16 '14 at 15:25
-
thanks Scott! That works like a charm. I had started looking at skipper, which seems like it will be awesome, but this just integrates much easier with the client side for now. keep up the awesome work on sails. – Alex Muro Jun 17 '14 at 01:51
-
@sgress454 I have a isAuthenticated middleware defined in the policies. How can I configure it in loadMiddleware so it runs before the bodyParser middleware except for some specific routes ? – Luc Oct 09 '14 at 14:43
-
1The `config.express.js` file has been deprecated. Middleware should now be added as described here: http://sailsjs.org/#/documentation/concepts/Middleware – dbasch Dec 23 '14 at 18:53
In the case of sails.js and jQuery File upload i think, you can replace sails bodyParser to jQuery file uploader post method, idea from this thread:
nginx / sails.js: incomplete file upload
below example works for me fine. sails js 0.10.5
npm install blueimp-file-upload-expressjs --save
npm install lodash --save
uncomment and add lines in the file /config/http.js:
middleware: {
cbodyParser: require('../cbodyParser')( { urls: [/\/uploads/]} ),
order: [
'startRequestTimer',
'cookieParser',
'session',
'myRequestLogger',
'cbodyParser', // intersept multipart requests
'bodyParser',
'handleBodyParserError',
'compress',
'methodOverride',
'poweredBy',
'$custom',
'router',
'www',
'favicon',
'404',
'500'
]
}
new file in root folder /cbodyParser.js:
var _ = require('lodash');
var options = {
tmpDir: __dirname + '/uploads/tmp',
publicDir: __dirname + '/uploads',
uploadDir: __dirname + '/uploads',
uploadUrl: '/uploads/',
maxPostSize: 11000000000, // 11 GB
minFileSize: 1,
maxFileSize: 10000000000, // 10 GB
acceptFileTypes: /.+/i,
inlineFileTypes: /\.(gif|jpe?g|png)$/i,
imageTypes: /\.(gif|jpe?g|png)$/i,
imageVersions: {
width: 220,
height: 220
},
accessControl: {
allowOrigin: '*',
allowMethods: 'POST',
allowHeaders: 'Content-Type, Content-Range, Content-Disposition'
},
nodeStatic: {
cache: 3600 // seconds to cache served files
}
};
var uploader = require('blueimp-file-upload-expressjs')(options);
function mime(req) {
var str = req.headers['content-type'] || '';
return str.split(';')[0];
}
// start jQuery file uploader here:
function parseMultipart(req, res, next) {
uploader.post(req, res, function (obj) {
res.send(JSON.stringify(obj));
});
next();
}
// check for post method in request
function disable_parser(opts, req, res) {
var matched = false;
try {
var method = null;
try {method = req.method.toLowerCase();}
catch(err){ /* */}
if(method) {
_(opts.urls).forEach(function(turl) {
if (method === 'post' && req.url.match(turl)) {
// console.log("matched"+ req.url);
if(!matched) matched = true;
};});
}
} catch(err) { debug(err);/* pass */ }
return matched;
}
// Start all stuff..
module.exports = function toParseHTTPBody(options) {
options = options || {};
// NAME of anynonymous func IS IMPORTANT (same as the middleware in config) !!!
return function cbodyParser(req, res, next) {
if (disable_parser(options, req, res) && mime(req) == 'multipart/form-data') {
// we found multipart request to /uploads, so we can use jQuery file uploader instead
return parseMultipart(req, res, next);
} else {
return next();
}
};
};

- 1
- 1

- 89
- 1
- 6