How to set dynamic route for static files in express - javascript

Currently, to serve static files im doing something like this:
app.use('/', express.static(__dirname + '/public/'));
// then i start the server
http.createServer(app).listen(port, function() {
console.log('HTTP Express server listening on port %s', port);
});
However, this sets the same directory for that path for every request, under all conditions. What I want to do is something like this that varies the response request to request:
http.createServer(app).listen(port, function() {
if (someCondition) {
app.use('/', express.static(__dirname + '/public/'));
}
else {
app.use('/', express.static(__dirname + '/public/someotherpath'));
}
console.log('HTTP Express server listening on port %s', port);
});
How can I do this?

You do it the other way around you modify url to make your desire effect
app.use('/', function(req,res,next){
if(condition){
req.url = newURL // add something to lead to different directory
}
next();
});
app.use('/', express.static(__dirname + '/public/'));
// then i start the server
http.createServer(app).listen(port, function() {
console.log('HTTP Express server listening on port %s', port);
});

Old question...but this is a quick solution...
If you want to keep all the functionality that comes with express.static, then you can just monkey-patch req.url (since it's just middleware):
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;
express.static(__dirname + '/static')(req, res, next);
});
// Just the asset.
app.use('/website/*', (req, res, next) => {
req.url = path.basename(req.originalUrl);
express.static(__dirname + '/static')(req, res, next);
});

the result of express.static() is a middleware function, so you can call it dynamically with your condition.
app.get('/', (req, res, next) => {
if (condition) {
express.static(__dirname + '/public/')(req, res, next);
} else {
express.static(__dirname + '/public/someotherpath')(req, res, next);
}
});

I also had that same problem now i fixed it by making a condition just like the below code
app.use("/", (req, res, next) => {
//check a condition if its false then return
if(1 !== 1)return
//After returned all conditions
next()
}, express.static("public"))
And this code checks if 1 is not 1 then wont show the files if 1 is 1 then it shows all public files :)

Based on your last comment: you can still do this within the router
app.get('/somepath', function(req, res){
if(req.someCondition){
res.sendFile('./path/to/appropriate/file.html');
} else {
res.sendFile('./path/to/different/file.html');
}
}
Leave express.static to serve your common files like js, css, and images. Send different html files using the .sendFile() method. This avoids having to use the renderer if you prefer not to use something like jade or ejs

Related

Routing on NodeJS Express

I'm developing a server in NodeJS with Express, but the web structure is a little bit complicate (I didn't do it, and I can't change it either).
The flow is something like this:
Node server receives a call like https://localhost/**{id}**.
The ID received is the folder's name where all files (html, js, css,
etc) are stored. By default, it returns index.html.
File structure of any web doesn't have a strict logic, means that could be more views at the same level the index.html is or in folders, wherever the clients wanted to develop them.
The issue I'm having is how to route the files correctly. Since I'm receiving the ID only when the index it's called, I couldn't figure out how to route links like View 1 or even the javascript files calls <script src='scripts/someGreatFunctions.js'></script> since they could also be in the root or in a folder (even the two things at the same time).
My server.js file:
const express = require('express');
const https = require('https');
const fs = require('fs');
const app = express();
const config = require('./config');
var webId;
var options = {
key: fs.readFileSync(config.paths.certificate.key),
cert: fs.readFileSync(config.paths.certificate.crt),
requestCert: false,
rejectUnauthorized: false
};
app.use(function (req, res, next) {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Credentials", "true");
res.setHeader("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS, POST, PUT");
res.setHeader("Access-Control-Allow-Headers", "Accept, Access-Control-Allow-Headers, Access-Control-Request-Headers, Access-Control-Request-Method, Authorization, Content-Type, Origin, X-Requested-With");
next();
});
app.get('/scripts/:script', function(req, res) {
res.sendFile(req.params.script, {root: config.paths.webs + webId + '/scripts'});
});
app.get('/:script.js', function(req, res) {
res.sendFile(req.params.script + '.js', {root: config.paths.webs});
});
// This routes correctly the index
app.get('/:id', function(req, res) {
webId = req.params.id;
res.sendFile('index.html', {root: config.paths.webs + webId});
});
// This DID NOT work
app.get('/:id/:page', function(req, res) {
//Some code here...
});
https.createServer(options, app).listen(443, function() {
console.log("NodeJS secure server started at port 443");
});
I am also in a learning phase. Hope this will help.
app.get('/test/:id/:page', function(req, res, next) {
let id = req.params.id;
let page = req.params.page;
console.log('The id: ' + id);
console.log('The page: ' + page);
});
I finally got the answer. Seems like it's very important the order in which gets are declared. Also, I used a regular expression to make it a little more generic.
/**
* HTTP GET for files (.html, .js, etc.) from another folder level
*/
app.get('/:id/:folder/:file', function(req, res) {
if (typeof(webId) === undefined) {
webId = req.params.id;
}
let folder = req.params.folder;
let file = req.params.file;
res.sendFile(file, {root: config.paths.webs + webId + '/' + folder});
});
/**
* HTTP GET for .js files from the base path
*/
app.get(/\/\w+.\b(js)/, function(req, res) {
let lastBar = req.url.lastIndexOf('/');
let script = req.url.substr(lastBar);
res.sendFile(script, {root: config.paths.webs});
});
/**
* HTTP GET for index page
*/
app.get('/:id', function(req, res) {
webId = req.params.id;
res.sendFile('index.html', {root: config.paths.webs + webId});
});
/**
* HTTP GET for view from base path
*/
app.get('/:id/:page', function(req, res) {
if (typeof(webId) === undefined) {
webId = req.params.id;
}
let page = req.params.page;
res.sendFile(page, {root: config.paths.webs + webId});
});

reloading the deep route after removing the '#' from url in express angular app throwing error [duplicate]

I would like to rewrite my URLs on my ExpressJS website. I've used this plugin, https://github.com/joehewitt/express-rewrite, but it doesn't work...
However, I might have made a mistake...
My app.js file :
var express = require('express')
, index = require('./routes/index.js')
, admin = require('./routes/admin.js')
, contact = require('./routes/contact.js')
, posts = require('./routes/posts.js')
, http = require('http')
, path = require('path')
, hash = require('./auth').hash
, db = require('./models')
, favicons = require('connect-favicons')
, rewriter = require('express-rewrite');
var app = express();
app.configure(function () {
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon(__dirname + '/public/images/FAVICON.ico'));
app.use(favicons(__dirname + '/public/images/apple-touch-icon.png'));
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.cookieParser());
app.use(express.cookieSession({
secret: 'SECRET',
cookie: { access: false }
})
);
app.use(rewriter);
app.use(app.router);
app.use(function(req, res, next){
res.render('404.jade', {
title: "404 - Page Not Found",
showFullNav: false,
status: 404,
url: req.url
});
});
});
app.configure('development', function () {
app.use(express.errorHandler());
});
app.get('/', index.index);
app.get('/toto', rewriter.rewrite('/heytoto'));
db.sequelize.sync().complete(function(err) {
if (err) {
throw err
} else {
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'))
})
}
});
My error message :
Express
500 TypeError: Object function app(req, res){ app.handle(req, res); } has no method 'match'
at Object.rewriter [as handle] (/Users/anthonycluse/Sites/Anthony-Cluse-Express/node_modules/express-rewrite/rewrite.js:3:26)
at next (/Users/anthonycluse/Sites/Anthony-Cluse-Express/node_modules/express/node_modules/connect/lib/proto.js:199:15)
at Object.cookieSession [as handle] (/Users/anthonycluse/Sites/Anthony-Cluse-Express/node_modules/express/node_modules/connect/lib/middleware/cookieSession.js:113:5)
at next (/Users/anthonycluse/Sites/Anthony-Cluse-Express/node_modules/express/node_modules/connect/lib/proto.js:199:15)
at Object.cookieParser [as handle] (/Users/anthonycluse/Sites/Anthony-Cluse-Express/node_modules/express/node_modules/connect/lib/middleware/cookieParser.js:60:5)
at next (/Users/anthonycluse/Sites/Anthony-Cluse-Express/node_modules/express/node_modules/connect/lib/proto.js:199:15)
at resume (/Users/anthonycluse/Sites/Anthony-Cluse-Express/node_modules/express/node_modules/connect/lib/middleware/static.js:60:7)
at SendStream.error (/Users/anthonycluse/Sites/Anthony-Cluse-Express/node_modules/express/node_modules/connect/lib/middleware/static.js:73:37)
at SendStream.EventEmitter.emit (events.js:126:20)
at SendStream.error (/Users/anthonycluse/Sites/Anthony-Cluse-Express/node_modules/express/node_modules/send/lib/send.js:147:51)
You could rewrite the URL before you get to the handler you want to use.
app.use(function(req, res, next) {
if (req.url === '/toto') {
req.url = '/heytoto';
}
next();
});
app.get('/heytoto', ...);
I've used a similar method to do URL rewrites with regular expressions.
So I had sort of the same issue. I wrote an app that uses the history API on browsers and I wanted to rewrite all non-static URLs back to index.html. So for static files I did:
app.configure(function() {
app.use('/', express.static(__dirname + '/'));
});
But then for the history API generated paths I did:
app.get('*', function(request, response, next) {
response.sendfile(__dirname + '/index.html');
});
This meant that any request that wasn't a file or directory in / (such as a URL generated by the history API) wouldn't be rewritten or redirected but instead the index.html file will be served and that then does all the JS routing magic.
Hopefully that's close to what you're looking for?
A solution that works without response.sendfile(..) is to use a rewrite middleware that is inserted prior to app.use(express.static(..)) like this:
// forward all requests to /s/* to /index.html
app.use(function(req, res, next) {
if (/\/s\/[^\/]+/.test(req.url)) {
req.url = '/index.html';
}
next();
});
// insert express.static(...)
This way, expressjs properly recognizes the rewrite. The static middleware will then take care of serving the file.
1) Your rewrite middleware must appear before the middleware/function that will handle the request.
Won't work:
app.use('/hello', () => sayHello() );
app.use(() => rewriteURLToHello()); //it's too late to try to rewrite a URL to /hello
Will work:
app.use(() => rewriteURLToHello()); //we can rewrite a URL to /hello
app.use('/hello', () => sayHello() ); //rewritten URL will be handled here
2) Your middleware must not be bound to the path you're trying to rewrite
Won't work:
app.use('/hello', (req, res, next) => {
//'/hello' has been trimmed from req.url
//req.url is / if the request was for /hello
req.url = '/goodbye'; //technically setting full path to /hello/goodbye
next(); //will only call other middleware in the /hello chain
});
app.use('/goodbye', () => sayBye()); //won't work
Will work:
app.use((req, res, next) => { //runs for every path. Same as .use('/',
//'/hello' has NOT been trimmed from req.url
//req.url is /hello if the request was for /hello
if (req.url.startsWith('/hello')) {
req.url = '/goodbye'; //full path now /goodbye
}
next(); //will continue calling all middleware
});
app.use('/goodbye', () => sayBye()); //will work
you could check the url with an if condition and use app.redirect to redirect to a certain url.
Try this:
app.get('/toto', function(req, res) {
res.redirect('/heytoto');
});

Serve different asset paths based on express js

I have a set of routes on express which are brands.
Id like to serve 2 asset directories to each of these brands.
One public/static for all brand routes and then everything thats under public/brands/brandName.
Is this possible ? I have something like this which seems to work but only for the first /brandName i request.
var express = require('express');
var app = express();
var path = require('path');
app.get('/brands/:brand', function (req, res) {
app.use(express.static(path.join(__dirname, 'public/brands/' + req.params.brand)));
res.sendFile(__dirname + '/public/static/index.html');
});
app.listen(process.env.PORT || 3000, function () {
console.log('listening on port 3000!');
});
app.use(express.static(path.join(__dirname, 'public/static')));
module.exports = app;
This should do the trick;
app.use('/brands', express.static(path.join(__dirname, 'public/brands/')));
app.use('/static', express.static(path.join(__dirname, 'public/static/')));
app.get('/brands/:brand', function (req, res) {
res.sendFile(__dirname + '/public/static/index.html');
});

Node + Express with static HTML. How to route all requests to index.html?

I am working on a single page web app using Node + Express and Handlebars for templating. Everything currently works well from index.html, which is served from a pretty standard server.js file:
var express = require('express');
var server = express();
server.use(express.static(__dirname + '/public'));
var port = 10001;
server.listen(port, function() {
console.log('server listening on port ' + port);
});
This works perfectly when loading from http://localhost:10001/. My issue is that I'm using push states in the app, so the browser may show a URL like http://localhost:10001/foo/bar and then if I refresh the page, I get the error Cannot GET /foo/bar since there is no route for this.
So my question, and pardon my incredible noobishness when it comes to Node, can I make it so all requests route to index.html? The JavaScript in my app can handle showing the right content based on URL params on page load. I don't want to define custom routes as the number would be large, and the paths for them can change dynamically.
const express = require('express')
const server = express()
/* route requests for static files to appropriate directory */
server.use('/public', express.static(__dirname + '/static-files-dir'))
/* other routes defined before catch-all */
server.get('/some-route', (req, res) => {
res.send('ok')
})
/* final catch-all route to index.html defined last */
server.get('/*', (req, res) => {
res.sendFile(__dirname + '/index.html');
})
const port = 8000;
server.listen(port, function() {
console.log('server listening on port ' + port)
})
This pattern will serve static assets before hitting the catch-all route that serves up your front-end application. To register any additional routes, just add them above the catch-all route.
var express = require('express');
var server = express();
// middleware
server.use(express.static(__dirname + '/public'));
// routes
server.use('*', function (req, res) {
// serve file
});
var port = 10001;
server.listen(port, function() {
console.log('server listening on port ' + port);
});
This short thing works well:
import express from "express";
const app = express(),
staticServe = express.static(`${ __dirname }/public`);
app.use("/", staticServe);
app.use("*", staticServe);
Just make sure that all URLs from your HTML/JS files are absolute now, as all resources that do not exist will return index.html file.
Express v 4.15.2
var app = express();
var options = {
dotfiles: 'ignore',
etag: true,
extensions: ['htm', 'html'],
index: 'index.html',
lastModified: true,
maxAge: '1d',
setHeaders: function (res, path, stat) {
res.set('x-timestamp', Date.now());
res.header('Cache-Control', 'public, max-age=1d');
}
};
app.use(compression());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(methodOverride());
app.use('/', express.static(__dirname + '/public', options));
app.use('*', express.static(__dirname + '/public', options));
var express = require('express');
var server = express();
server.use(express.static(__dirname + '/public'));
server.get('*', function(req, res){
res.sendFile('index.html');
});
var port = 10001;
server.listen(port, function() {
console.log('server listening on port ' + port);
});

extend expressjs res property

Currenty I am trying to add an error & notice function to my expressjs app. I thought that by calling
app.use(function (req, res, next) {
res.notice = function (msg) {
res.send([Notice] ' + msg);
}
});
the notice function would be attached to all res objects present in my application, enabling me to use it as follows:
app.get('something', function (req, res) {
res.notice('Test');
});
However, the example above does not work. Is there a way to accomplish what I'm trying to do?
You need to call next after adding notice method to res, and you need to add the middleware before routes definition.
var express = require('express');
var app = express();
app.use(function (req, res, next) {
res.notice = function (msg) {
res.send('[Notice] ' + msg);
};
next();
});
app.use(app.router);
app.get('/', function (req, res) {
res.notice('Test');
});
app.listen(3000);

Categories

Resources