Any way to serve static html files from express without the extension? - node.js

I would like to serve an html file without specifying it's extension. Is there any way I can do this without defining a route? For instance instead of
/helloworld.html
I would like to do just
/helloworld

you can just use extension option in express.static method .
app.use(express.static(path.join(__dirname, 'public'),{index:false,extensions:['html']}));

A quick'n'dirty solution is to attach .html to requests that don't have a period in them and for which an HTML-file exists in the public directory:
var fs = require('fs');
var publicdir = __dirname + '/public';
app.use(function(req, res, next) {
if (req.path.indexOf('.') === -1) {
var file = publicdir + req.path + '.html';
fs.exists(file, function(exists) {
if (exists)
req.url += '.html';
next();
});
}
else
next();
});
app.use(express.static(publicdir));

While Robert's answer is more elegant there is another way to do this. I am adding this answer just for the sake of completeness. To serve static files without extension you can create a folder with the name of the route you want to serve against and then create an index.html file in it.
Taking my own example if I wanted to serve hello.html at /hello. I would create a directory called hello and put an index.html file in it. Now when '/hello' is called express will automatically serve this file without the extension.
Kind of obvious as this is supported by all web frameworks but I missed it back then.

This single line can route all the html file extension in the public folder.
app.use(express.static('public',{extensions:['html']}));

If you want to go the reverse way like I did(serving an html file called "helloworld" as html) this is the middleware I used.
var express = require('express');
var app = express();
app.use(function(req, res, next) {
if (req.path.indexOf('.') === -1) {
res.setHeader('Content-Type', 'text/html');
}
next();
});
app.use('/', express.static(__dirname + '/public'));
app.listen(8080, function () {
console.log('App listening on port 8080!');
})

Related

Intercept request for a static file in express.js

I have a node server, that serves static files in a PUBLIC folder like this:
var app = express();
app.listen(port);
app.use(compression());
app.use(express.static(__dirname + '/PUBLIC'));
There is a json file, let's say important.json that is located in /PUBLIC folder. This is being served as a static file
Now, I want to intercept request for this /PUBLIC/important.json, so that I can programatically return a random json structure instead.
None of the followings works:
app.get('/PUBLIC/important.json', function(req, res) {
console.log("caught1!")
});
app.get(__dirname + '/PUBLIC/important.json', function(req, res) {
console.log("caught2!")
});
app.get('important.json', function(req, res) {
console.log("caught3!")
});
How can I intercept request for that partically static file?
As the express.static middleware does not call the next middleware using next(), the definition order is important. You have to define your own middleware before using express.static.
app.get('/PUBLIC/important.json', (req, res, next) => {
console.log('caught');
next();
});
app.use(express.static(__dirname + '/PUBLIC'));
Could you tell us a bit more about your stack ?
Are you using nginx / apache to proxy_pass the traffic to your nodejs server ?
Are you just running your app with "node app.js"
Let's try to add this simple route in your application :
app.get('/', function (req, res) {
res.send('Hello World!');
});
And try to access it by removing URI parameters ? Does the "Hello world" show up ?
I just want to be sure the traffic is actually treated by your node app.
Your route definition is supposed to work for your actual request.

NodeJS Express Root Path

In NodeJS Express module, specifying path "/" will catch multiple HTTP requests like "/", "lib/main.js", "images/icon.gif", etc
var app = require('express')
app.use('/', authenticate);
In above example, if authenticate is defined as followed
var authenticate = function(request, response, next) {
console.log("=> path = " + request.path);
next()
}
Then you would see
=> path = /
=> path = /lib/main.js
=> path = /images/icon.gif
Could anyone advise how to define path in Express "app.use" that only catch "/"?
If you are trying to expose static files, people usually place those in a folder called public/. express has built-in middleware called static to handle all requests to this folder.
var express = require('express')
var app = express();
app.use(express.static('./public'));
app.use('/', authenticate);
app.get('/home', function(req, res) {
res.send('Hello World');
});
Now if you place images/css/javascript files in public you can access them as if public/ is the root directory
<script src="http://localhost/lib/main.js"></script>
As far as I understand, what you need to do is if you have '/' & '/abc' you need to catch it separately.
This will do the trick:
app.use('/abc', abc);
app.use('/', authenticate);
Means, register the /abc middleware first, then do the / middleware.
There is an issue with this solution also. Here we declared /abc only. So when user calls an unregistered path, then it will hit here.
You can make use of originalUrl property in request object to determine its / only or there is something else. Here is the documentation for this : http://expressjs.com/en/api.html#req.originalUrl
if(req.originalUrl !== '/'){
res.status(404).send('Sorry, we cannot find that!');
}
else{
/*Do your stuff*/
}

Unable to serve image (png) with node.js and express

I've studied similar questions on SO but haven't found a solution to my problem... I've set up an express route to serve images but I can't get it to return an image from where it's stored. Notice I've included a statement to allow requests from any origin. What happens is that when I make a request to http://localhost:8080/images/x10.png the response I get is an empty image element with src="http://localhost:8080/images/x10.png instead of from http://ubuntubox.dev/images/x10.png, which is where the image is actually located and is the path I'm ultimately passing to the request method. What am I missing? Thanks.
app.get('/images/*', function(req, res, path){
var imagePath = req.url,
url = 'http://ubuntubox.dev' + imagePath;
request(url, function(error, response, img) {
if(!error && response.statusCode === 200) {
res.header('Access-Control-Allow-Origin', '*');
res.writeHead(200, {'Content-Type': 'image/png' });
res.end(img, 'binary');
} else if(response.statusCode === 404) {
res.status(404);
res.type('txt').send('oops');
}
});
}).listen(8080, '127.0.0.1');
I don't know if you still have this problem, but..
The solution for your problem is just putting a .pipe(res) and it will send the file to the response
app.get('/images/*', function(req, res, path){
var imagePath = req.url,
url = 'http://ubuntubox.dev' + imagePath;
request(url).pipe(res);
}).listen(8080, '127.0.0.1');
If you want to serve images and other assets in a way that makes sense and doesn't require you to write a million routes, try this:
Create a new folder "public" and move all of your assets into it.
Open server.js and add the following line:
app.use(express.static('public'))
Your assets should now be available like so:
http://localhost:3000/images/kitten.jpg
http://localhost:3000/css/style.css
http://localhost:3000/js/app.js
http://localhost:3000/images/bg.png
http://localhost:3000/hello.html
Soure: https://expressjs.com/en/starter/static-files.html
Just figured this out for myself in express 4
app.get('/images/img1.png', function(req, res){
res.sendFile('/Absolute/path/to/the/file/images/img1.png');
});
user2879041 has already answered what he found useful, still I would think of another way for serving images, (where I shall not write a route for each file manually and the send the file to the browser).
As you are already using express, just server tyhe static images directly, you have already got that in express.static
app.use(express.static('/Absolute/path/to/the/file/images/img1.png'));
benefit of using express.static is that you would just keep adding the images inside the folder you want to be static and express will serve the images for you(no need to add any code).
I am not sure if it's the same case or not.
But here is my answer:
var path = require('path');
var express = require('express');
var app = express();
var dir = path.join(__dirname, 'public');
app.use('/public', express.static(dir));
app.listen(3000, function () {
console.log('Listening on http://localhost:3000/');
});
Notice this line:
app.use('/public', express.static(dir));
You need to add the path again with the app.use method
I don't get the idea of adding this part, but it was the only way to make it works.
and without it keeps responding 'Error' and I can not access this file.
hopefully, I could help you.

Serve Static Files on a Dynamic Route using Express

I want to serve static files as is commonly done with express.static(static_path) but on a dynamic
route as is commonly done with
app.get('/my/dynamic/:route', function(req, res){
// serve stuff here
});
A solution is hinted at in this comment by one of the developers but it isn't immediately clear to me what he means.
Okay. I found an example in the source code for Express' response object. This is a slightly modified version of that example.
app.get('/user/:uid/files/*', function(req, res){
var uid = req.params.uid,
path = req.params[0] ? req.params[0] : 'index.html';
res.sendFile(path, {root: './public'});
});
It uses the res.sendFile method.
NOTE: security changes to sendFile require the use of the root option.
I use below code to serve the same static files requested by different urls:
server.use(express.static(__dirname + '/client/www'));
server.use('/en', express.static(__dirname + '/client/www'));
server.use('/zh', express.static(__dirname + '/client/www'));
Although this is not your case, it may help others who got here.
You can use res.sendfile or you could still utilize express.static:
const path = require('path');
const express = require('express');
const app = express();
// Dynamic path, but only match asset at specific segment.
app.use('/website/:foo/:bar/:asset', (req, res, next) => {
req.url = req.params.asset; // <-- programmatically update url yourself
express.static(__dirname + '/static')(req, res, next);
});
// Or just the asset.
app.use('/website/*', (req, res, next) => {
req.url = path.basename(req.originalUrl);
express.static(__dirname + '/static')(req, res, next);
});
This should work:
app.use('/my/dynamic/:route', express.static('/static'));
app.get('/my/dynamic/:route', function(req, res){
// serve stuff here
});
Documentation states that dynamic routes with app.use() works.
See https://expressjs.com/en/guide/routing.html

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