How can I use middleware alongside express.static? - node.js

I have a nodejs application that serves a single page app via express.static. This all works fine, however when I try and create a simple piece of middleware:
app.use(function(req, res, next){
console.log('%s %s', req.method, req.url);
next();
});
app.use(express.static(path.join(__dirname, 'client')));
any attempt to load content from client fails with:
TypeError: Object function (req, res, next){
console.log('%s %s', req.method, req.url);
next();
} has no method 'concat'
If I use the middleware after the express.static call it works fine - but isn't called for static content. I need to setup the middleware so that any flash messages (from connect flash) can be sent as cookies to the static content.
Does anyone know how I can use middleware for all content, including static content? Eventually I'll be serving two folders, one public and one private (authenticated via passport).

I've put together a minimal implementation of your question and it works for me:
var express = require('express')
var path = require('path')
var app = express()
app.use(function(req, res, next) {
console.log('Middleware says %s %s', req.method, req.url);
next();
})
app.use(express.static(path.join(__dirname, 'client')))
app.listen(8080, function() {
console.log('server is ready')
})
I then started the server
$ node so.js
server is ready
and loaded http://localhost:8080/foo.txt in my browser
Middleware says GET /foo.txt
I'm using Express 3.6.0 - if you're using an older version of Express then you may well have stumbled across a bug that's since been fixed, similar to this one. If updating doesn't solve your problem then I would recommend updating your question to contain more code, perhaps a runnable, yet minimal example of the issue. Hope this helps!

Related

nodejs post method not getting called

I found my question was asked a year ago here app.post() not working with Express but the code written there is outdated (the way bodyparser was added doesn't work anymore as well as function mentioned below) plus the asker never chose an answer so the question was never solved.
Here's my code
const express = require("express");
const db = require("mysql");
const app = express();
const bodyParser = require("body-parser");
const multer = require("multer"); // v1.0.5
const upload = multer(); // for parsing multipart/form-data
const http = require("http");
const path = require("path");
app.set("view engine", "jade");
app.set("views", path.join(__dirname));
console.log("before");
app.listen(8000, () => {
console.log("Server started!");
console.log("within");
});
console.log("after");
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
app.post("/", function(req, res) {
console.log("hit here in post");
res.render("index.jade", {});
console.log("hit here in post");
res.json({ name: "John" });
res.status(500).json({ error: "message" });
res.end();
});
app.get("/", function(req, res) {
res.render("index.jade", {});
console.log("hit here in get");
console.log(req.body);
});
Here's the output.
before
after
Server started!
within
hit here in get
{}
I even tried to wrap the app sets and uses in app.configure like the asker of the other question to see if that was the issue but that configure function doesn't seem to exist anymore because I got an error about it.
Also I should probably note. My routing here is correct. I haven't made a views subfolder yet so that's why I have it written as it is.
Update
I think I may have spotted the issue but I don't understand why it's occurring. In the network tab of the browser I see that GET is getting 404 error because of a favicon.ico request but I don't understand where that request is coming from. I've seen the serve-favicon npm module to support it but didn't want to added because I never intended to add a favicon image to my server. I don't even understand how that would work.
Reply to last comment by James
What do you mean by I configure the middleware after it has started? Are you referring to the fact that the post method is written after port listening has started? Also if that's the reason why post isn't executing how come the get method executes regardless of that? I'm not holding back any server code aside from code I currently have commented out for the moment but that code I posted is my main index.js file and it's the only file I modified from the standard npm init project. I haven't setup any routes because I don't see the need to do so (even when I add react since my project is simple in concept of communication between reactjs, nodejs and a database "hence my frustration") which is why I'm trying to have get and post only access the root directory.
favicon is automatically requested by the browser. it is the icon used in the browser tab or url address bar
Add this, before app.get():
app.all('/', function(req, res, next) {
console.log({method: req.method, url: req.url});
next();
});

Calling Express by hand

In a node.js/express/socket.io application, how does one "call" express by hand to load/render the home page without saying app.use(blah). In other words, if I wanted to tell express to load index.html by hand instead of automatically.
var express = require('express'),
app = express(),
...
//app.use magically loads index.html when the browser hits 8080
app.use(express.static(path.join(__dirname, '../client/www'))); //index.html is in www
var port = process.env.PORT || 8080; //select your port or let it pull from your .env file
//===============PORT=================
http.listen(port, function () {
console.log('listening on: ' + port);
}
Where index.html is in www ? This doesn't work:
app.get('/', function(req, res){
res.sendfile('index.html', { root: __dirname + "/relative_path_of_file" } );
});
Nor this:
app.get('/', function(req, res){
res.render('/home/idf/Documents/js/react-trader/client/www/index.html', {user: req.user});
});
I was able to resolve the problem that is the cause of this question. I am using Passport to authenticate Express. I needed to protect the home page (index.html), so I added a route and ensured that the user had to be authenticated to view that page. So I said:
app.get('/index.html', ensureAuthenticated, function(req, res){
...
}
The problem is that if I do this, when the user authenticates, I couldn't figure out how to pass control to Express. I either could authenticate (and prevent accessing the home page) through Passport routing, or I could do Express. But I couldn't do both.
It turns out the answer is really simple (or at least in my very limited understanding at this point) I got to work by simply rewriting to
app.get('/index.html', ensureAuthenticated, function(req, res, next){
return next();
}
In essence, the way to break out of Passport routes and pass control to Express [or "call it by hand" - hence my question] is to return next();
This is not obvious at all, and it took quite a bit of experimentation to get it to work.

.on('connection') for an express server

I am trying to create a basic web server with express for node.js. I know that the http module has a .on('connection',function(client){}) method that is called whenever a client connects. Is there a similar method for express?
I know this question is quite old, but I had the same one and was able to figure out the answer, so I thought I would post it here for anyone else who may be looking.
According to the Express docs with Express 4.x, the listen method returns an http.Server object, so all methods that can be used on http.Server.listen are also available on the Express listen method.
With this in mind, the answer to your question is yes, and below is an example of how you can achieve it in Express 4.x.
const app = express();
app.use('/', function (req, res, next) {
// Add your code for this route here
});
const server = app.listen(3000, function () {
console.log('Server listening on port 3000');
});
server.on('connection', function (client) {
// Do your thang here
});
You can easily add a route that will be matched against "everything", that is:
app.use('/', function (req, res, next) {
console.log("received request: " + req.originalUrl);
next();
});
This is simply a middleware that, once a client executes any rest api to your server, will log the url and call next() to continue to the next matching route

Using express.static middleware in an authorized route

I'm using node with express and passportjs to restrict access to files located in a private folder. I have reduced my code to the following.
Everything in the public static folder works great but route targeting the private folder through the use of the staticMiddleware returns 404 errors.
var express = require('express')
, util = require('util');
var app = express.createServer();
var staticMiddleware = express.static(__dirname + '/private');
app.configure(function() {
app.use(app.router);
app.use(express.logger('dev'));
app.use('/public',express.static(__dirname + '/public'));
});
app.get('/private/:file', function(req, res, next){
console.log('about to send restricted file '+ req.params.file);
staticMiddleware(req, res, next);
});
app.listen(16000);
I was using the following references that seems to work for others, so I must be missing something.
It won't work for me showing only 404 responses for the content located in the private area.
Node.js module-specific static resources
NodeJS won't serve static files, even when using express.static
Redirecting to a static file in express.js
I could have sworn I had this working before, maybe it was broken in a new version of something.
Node v0.8.1
npm 1.1.12
express#2.5.11
connect#1.9.2
sheesh staring at me the whole time
app.get('/private/:file', function(req, res, next){
console.log('about to send restricted file '+ req.params.file);
req.url = req.url.replace(/^\/private/, '')
staticMiddleware(req, res, next);
});
Edit 11-29-2014
So after someone posted to the question I came back to this answer to find that even though I mention passportjs I never showed how I ended up using this function.
var staticMiddlewarePrivate = express['static'](__dirname + '/private');
app.get('/private/*/:file', auth.ensureAuthenticated, function(req, res, next){
console.log('**** Private ****');
req.url = req.url.replace(/^\/private/, '');
staticMiddlewarePrivate(req, res, next);
});
You can also add express.static(__dirname + '/private'); to your app.config.
app.configure(function() {
app.use(app.router);
app.use(express.logger('dev'));
app.use('/public',express.static(__dirname + '/public'));
app.use('/private',express.static(__dirname + '/private'));
});
The private path middleware would be executed anytime a path began with private.

Is it possible to set a base URL for NodeJS app?

I want to be able to host multiple NodeJS apps under the same domain, without using sub-domains (like google.com/reader instead of images.google.com). The problem is that I'm always typing the first part of the url e.g. "/reader" in Express/NodeJS.
How can I set up an Express app so that the base URL is something.com/myapp?
So instead of:
app.get("/myapp", function (req, res) {
// can be accessed from something.com/myapp
});
I can do:
// Some set-up
app.base = "/myapp"
app.get("/", function (req, res) {
// can still be accessed from something.com/myapp
});
I'd also like to configure Connect's staticProvider to behave the same way (right now it defaults to serving static files to something.com/js or something.com/css instead of something.com/myapp/js)
The express router can handle this since 4.0
http://expressjs.com/en/api.html#router
http://bulkan-evcimen.com/using_express_router_instead_of_express_namespace.html
var express = require('express');
var app = express();
var router = express.Router();
// simple logger for this router's requests
// all requests to this router will first hit this middleware
router.use(function(req, res, next) {
console.log('%s %s %s', req.method, req.url, req.path);
next();
});
// this will only be invoked if the path ends in /bar
router.use('/bar', function(req, res, next) {
// ... maybe some additional /bar logging ...
next();
});
// always invoked
router.use(function(req, res, next) {
res.send('Hello World');
});
app.use('/foo', router);
app.listen(3000);
Previous answer (before express 4.0) :
The express-namespace module (dead now) used to do the trick :
https://github.com/visionmedia/express-namespace
require('express-namespace');
app.namespace('/myapp', function() {
app.get('/', function (req, res) {
// can be accessed from something.com/myapp
});
});
At the moment this is not supported, and it's not easy to add it on your own.
The whole routing stuff is buried deep inside the server code, and as a bonus there's no exposure of the routes them selfs.
I dug through the source and also checked out the latest version of Express and the Connect middleware, but there's still no support for such functionality, you should open a issue either on Connect or Express itself.
Meanwhile...
Patch the thing yourself, here's a quick and easy way with only one line of code changed.
In ~/.local/lib/node/.npm/express/1.0.0/package/lib/express/servers.js, search for:
// Generate the route
this.routes[method](path, fn);
This should be around line 357, replace that with:
// Generate the route
this.routes[method](((self.settings.base || '') + path), fn);
Now just add the setting:
app.set('base', '/myapp');
This works fine with paths that are plain strings, for RegEx support you will have to hack around in the router middleware yourself, better file an issue in that case.
As far as the static provider goes, just add in /mypapp when setting it up.
Update
Made it work with RegExp too:
// replace
this.routes[method](baseRoute(self.settings.base || '', path), fn);
// helper
function baseRoute(base, path) {
if (path instanceof RegExp) {
var exp = RegExp(path).toString().slice(1, -1);
return new RegExp(exp[0] === '^' ? '^' + base + exp.substring(1) : base + exp);
} else {
return (base || '') + path;
}
}
I only tested this with a handful of expressions, so this isn't 100% tested but in theory it should work.
Update 2
Filed an issue with the patch:
https://github.com/visionmedia/express/issues/issue/478
Just to update the thread, now with Express.js v4 you can do it without using express-namespace:
var express = require('express'),
forumRouter = express.Router(),
threadRouter = express.Router(),
app = express();
forumRouter.get('/:id)', function(req, res){
res.send('GET forum ' + req.params.id);
});
forumRouter.get('/:id/edit', function(req, res){
res.send('GET forum ' + req.params.id + ' edit page');
});
forumRouter.delete('/:id', function(req, res){
res.send('DELETE forum ' + req.params.id);
});
app.use('/forum', forumRouter);
threadRouter.get('/:id/thread/:tid', function(req, res){
res.send('GET forum ' + req.params.id + ' thread ' + req.params.tid);
});
forumRouter.use('/', threadRouter);
app.listen(app.get("port") || 3000);
Cheers!
I was able to achieve this using a combination of express-namespace for the routes and a fix from the below google group discussion for the static assets. This snippet will treat a request to /foo/javascripts/jquery.js like a request to /javascripts/jquery.js:
app.use('/foo', express.static(__dirname + '/public'));
Source:
https://groups.google.com/forum/#!msg/express-js/xlP6_DX6he0/6OTY4hwfV-0J
I know this is a very old question but Express has changed a lot since most these answers were posted so I thought I'd share my approach.
You can, of course, use Routers with Express 4 to group together related functionality behind a particular path. This is well documented and has already been covered by other answers.
However, it is also possible to mount an entire application at a particular path. As an example, let's assume our application (the one we want to host at /myapp) looks like this, in a file called myapp.js:
var express = require('express'),
path = require('path'),
app = express();
app.use(express.static(path.join(__dirname, 'public')));
app.get('/hello', function(req, res) {
res.send('Hello');
});
// Lots of other stuff here
exports.app = app;
In our main js file we could then mount this whole application at the path /myapp:
var express = require('express'),
app = express(),
myApp = require('./myapp').app;
app.use('/myapp', myApp);
app.listen(3000);
Note that we've created two applications here, one mounted on the other. The main application could have further sub-apps mounted at different paths as required.
The code in myapp.js is completely independent of where it was mounted. It's similar to the structure used by the express-generator in that regard.
Some documentation about sub-apps can be found here:
https://expressjs.com/en/4x/api.html#app.mountpath
https://expressjs.com/en/4x/api.html#app.onmount
There are also reliability issues. If reliability is important, a common solution is to use a front-end reverse HTTP proxy such as nginx or HAProxy. They both use single-thread evented architecture and are thus very scalable.
Then you can have different node processes for different subsites, and if one site fails (uncaught exception, memory leak, programmer error, whatever) the rest of sub-sites continue to work.
I was looking for this feature but for API routes, not for static files. What I did was that when I initialized the router, I added the mount path. So my configuration looks like this
//Default configuration
app.configure(function(){
app.use(express.compress());
app.use(express.logger('dev'));
app.set('json spaces',0);
app.use(express.limit('2mb'));
app.use(express.bodyParser());
app.use('/api', app.router); // <---
app.use(function(err, req, res, callback){
res.json(err.code, {});
});
});
Notice the '/api' when calling the router

Resources