using express.js for a project, first time using it for much more than messing around, and having some trouble with getting middleware to play nice.
My problem is that calls to my express static route, declared close to the top of the file
app.use(express.static(__dirname + '/public'));
are actually being handled by the error handler, almost at the bottom of the file
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
...and I'm unsure why. I know that JS isn't necessarily executing stuff in order, but it was my understanding that express will execute these in order, and app.use stuff at the bottom will occur after app.use stuff at the top - hence the need for next(); - to pass to the next app.use handler?
Any ideas/wisdom? Any help appreciated.
I have this code:
// Initial variable setup
var
express = require('express'),
favicon = require('serve-favicon'),
logger = require('morgan'),
cookieParser = require('cookie-parser'),
bodyParser = require('body-parser'),
swig = require('swig'),
stylus = require('stylus'),
nib = require('nib'),
fs = require('fs'),
app = express()
;
app.use(express.static(__dirname + '/public'));
app.engine('html', swig.renderFile);
app.set('view engine', 'html');
(settings.deploymentMode === 'dev') && app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
function compile(str, path) {
console.log('STYLUS: Compiling CSS');
return stylus(str)
.set('filename', path)
.set('compress', true)
.use(nib())
.import('nib');
}
app.use(stylus.middleware(
{
src: __dirname + '/public',
compile: compile
}
));
// Got some routing going on here... app.get statements, all working fine.
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('system/error', {
message: err.message,
error: err
});
});
} else {
// Production error handler - #TODO: Rewrite this one first.
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('system/error', {
message: err.message,
error: {}
});
});
}
module.exports = app;
Express error handling middleware is defined using four params, not three.
// From the specs
app.use(function(err, req, res, next){
console.error(err.stack);
res.status(500).send('Something broke!');
});
If you only defined it with 3 params, then it considers it a "normal" middleware and will call it unless a previous middleware, ends the request instead of calling next(). It appears that static middleware calls next(), probably to allow later middleware to log or compress its data.
Related
I'm having trouble with my node.js express routes. I'm really new to it and I can't see my mistake. I'm always getting a 404 Error when requesting localhost:2700/api/subs, but I think that my route is correct, isn't it? Can anybody see a mistake?
Beginning of the Error Message:
Error: Not Found
at ****/app.js:45:13
at Layer.handle [as handle_request] (****/node_modules/express/lib/router/layer.js:95:5)
Here is the app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
const mongoose = require('mongoose');
// establish connection to the Database
mongoose.connect('mongodb://localhost/test', {
useMongoClient: true
});
mongoose.connection.once('open', function() {
console.log('Connection to Database has been established..');
}).on('error', function(error){
console.log(error);
});
var index = require('./routes/index');
var users = require('./routes/users');
Subscriber = require('./routes/subscriber.js');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', index);
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
app.get('/api/subs', function(req, res){
Subscriber.getSubscribers(function(err, subscribers){
if(err){
throw err;
}
res.json(subscribers);
});
});
// ... here is a function which creates the database objects and saves
// them. took it out for better overview....
app.listen(2700, function(){
console.log("Listening on Port 2700")
});
module.exports = app;
and the subscriber.js which is in the subdirectory ./routes:
const mongoose = require('mongoose');
var subscriberSchema = mongoose.Schema({
//seqnr shall go here. dunno how to declare integer x)
nr: Number,
name: String,
email: String,
uLink: String,
anwalt: String
});
var Subscriber = module.exports = mongoose.model('Subscriber', subscriberSchema);
//get Subscriber
module.exports.getSubscribers = function(callback, limit){
Subscriber.find(callback).limit(limit);
};
index.js
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
You need to put your 404 app.use after all the other uses, otherwise it will ignore the api/subs after it.
Also, this bit will never run, because it also comes after an api.use that will always throw an error:
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
Plus, you really shouldn't be throwing errors for 404s. It should tell the end user the page doesn't exist, but it shouldn't crash your script.
Also I agree with the other answer that says you should move those code blocks into separate router files, but that's more for good practice and structuring than for this particular bug.
Try putting it in a separate file and including it where you do with other routes, before the 404 handler
app.use('/', index);
app.use('/users', users);
So... make a subs.js route
var express = require('express');
var router = express.Router();
Subscriber = require('./routes/subscriber.js');
router.get('/', function(req, res){
Subscriber.getSubscribers(function(err, subscribers){
if(err){
throw err;
}
res.json(subscribers);
});
});
module.exports = router;
Then include it in your app.js
var subs= require('./routes/subs');
...
api.use('/api/subs', subs);
...
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
I have this about.js route and it works fine but I don't understand how / in router.get() would work while /about wouldn't?
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
res.render('about', { title: 'About' });
});
module.exports = router;
----------------- UPDATE ----------------------
It's basically what I got out of the box after installing express.js
except the about lines.
I expected router.get('/about' ...) in about.js would work but it threw an error and it worked with / instead and that's what bugs me.
app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var users = require('./routes/users');
var about = require('./routes/about');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
app.use('/about', about);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
The problem
When you define a route on your app.js as you did with app.use('/about', about);. You are already telling express that you expect requests to hit http://yourserver/about route.
If you try to define /about again inside your about.js with:
router.get('/', function(req, res, next) {
res.render('about', { title: 'About' });
});
What you're doing is tellig the Express that you will hit a /about inside your firstly declared /about. So it will expect requests on this route: http://yourserver/about/about
The solution
It's actually what you're using. Define a root route inside your about.js as:
router.get('/', function(req, res, next) {
res.render('about', { title: 'About' });
});
This way your app will be:
Modular since you're using different files for different routes (about.js, users.js)
Easier to read
With simplier routes inside each file, since you don't need to type /about everytime you wish to create a new route.
If you wish a http://yourserver/about/help simply add a handler inside your route file about.js as here:
router.get('/help', function(req, res, next) {
res.render('help', { title: 'Help' });
});
If you want the route /about work then you have to create another route:
router.get('/about', function(req, res, next) {
res.render('about-page', { title: 'About' });
});
because / will only work for the home page.
I´m currently trying to render my .ejs-templates with some variables, but I´m kinda stuck and can`t help myself. I´ve installed express over the express-generator with compass and ejs.
In my routes/index.js
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.write('Hello World')
res.end();
});
module.exports = router;
So I want to render <%= name %> in index.ejs (views/index.ejs) with the name Jack. In a few tutorials it should work this way, but it just don`t works for me.
I got an error telling me that the variable name is not defined. Would be very nice, if you guys could tell me, what I´m doing wrong or what I´ve missed.
I´m using ejs the first time and just can`t figure out my mistake =/
This is my app.js server-file
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var http = require("http");
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(require('node-compass')({mode: 'expanded'}));
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
regards,
Cab
edit: I figured out that the rendering of the variable title works, but all the other variables don`t work. I can imagine, that I can only access some kind of global variables and title is one of them =/
edit2: Found out, that my routing isnt working properly ... so the rendering isnt working ofc. But can`t figure out my mistake =/
If you have split your project up into different modules then you need to export those modules so they are available in other parts of your app.
For example you have separate route modules where you are defining your routes. For these to be available to the rest of your app then you need to make them available using the module.exports command.
so at the end of routes/index.js you need to have
module.exports = router;
The end of the express page on routing gives an example
Though I have read quite a few questions being answered on stackoverflow, I'm still unable to get it to work even after a couple of days of trying. It's my first week with express and node and so I don't know if I'm doing the small things right. I basically want to upload a file and later on save it to the file system, however, I'm unable to proceed with req.files giving me undefined. Please see my code below.
This is my app.js
var express = require('express');
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var routes = require('./routes/index');
var users = require('./routes/users');
var upload = require('./routes/upload.js');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
app.use('/upload', upload);
/// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
/// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
This is my routes/upload.js
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res) {
console.log("");
console.log(req.files);
res.send('this is the page you get upon doing file upload');
});
module.exports = router;
This is my views/homepage.jade
doctype html
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body
p select file to upload
form(action="upload", method="get", enctype="multipart/form-data")
input(type="file", name="displayImage")
input(type="submit")
At the moment, I'm hearing a lot of terms like multer, connect-busboy, bodyParser being deprecated from express4 etc but with no real idea on how to proceed. Please advise me on how I can proceed and what code should be added.
Thanks.
You need a middleware module that can parse your uploaded file.
Like such:
https://github.com/expressjs/multer
https://github.com/mscdex/connect-busboy
Then use the middleware in your index.js, like:
app.use(multer({ dest: './uploads/'}))
or
app.use(busboy());
A number of modules were removed from Express in 4.0 and are now separate packages you have to include. The easiest way to get started with it is to use express-generator to generate the scaffolding for you. This will include and require the correct packages for parsing cookies, and the request body. It doesn't include a file parser however. I put together an example using multer and put it on Github for you to reference.
After you clone it, you can run npm install, and then npm start.
One other thing you were doing incorrectly that I fixed was using app.get for your upload handler. You can't use GET to upload a file. In my example I changed this to a POST request. Here are the relevant snippets.
app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var multer = require('multer');
var routes = require('./routes/index');
var users = require('./routes/users');
var upload = require('./routes/upload');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(multer({ dest: './uploads/'}))
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
app.use('/upload', upload);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
index.jade
extends layout
block content
h1= title
p select file to upload
form(action='upload', method='post', enctype='multipart/form-data')
input(type='file', name='displayImage')
input(type='submit')
Im currently very new to Node.js - Express framework and Im trying to emulate a MVC pattern, so far I got this
app.js
var express = require('express');
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var http = require('http');
var app = module.exports = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.set('port', process.env.PORT || 3000);
app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
require('./routes');
/// catch 404 and forwarding to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
/// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
http.createServer(app).listen(app.get('port'), function() {
console.log("Running server");
});
Just a normal app.js generated with the express generator with some modifications, now my routes/index.js
app = require('../app');
app.get('/test', function(req, res) {
require('./controllers/test.js');
test();
});
app.get('/', function(req, res) {
res.send('yankevf');
});
As you can see on route /test if looks for module /controllers/test.js but since theres no actual module it wont work..
How can I include a file that is inside the folder controllers? since my server keeps searching inside node_modules
It looks like you're basically there...
From your question it sounds like your folder structure is:
./app.js
./routes
-> index.js
./controllers
-> test.js
If that's the case, this should work:
app = require('../app');
app.get('/test', function(req, res, next) {
test = require('../controllers/test.js'); // Note the path, one directory up
// Passing the req, res, next arguments on to your controller allows it to respond
// i.e. res.json({msg: 'hello world'}).
test(req, res, next);
});
Although you probably don't want to load your controller on every new request, but rather load (require) it once, and call it on every request:
app = require('../app');
testController = require('../controllers/test.js');
app.get('/test', function(req, res, next) {
// Passing the req, res, next arguments on to your controller allows it to respond
// i.e. res.json({msg: 'hello world'}).
testController(req, res, next);
});
If you're directly passing these arguments to your controller (like you should), you can write it more succinctly:
app = require('../app');
testController = require('../controllers/test.js');
// Call your controller, automatically passing 'req', 'res', 'next' arguments.
app.get('/test', testController);
For a full example which automates the mounting of routes, checkout: Express MVC example