Node.js Serving HTML pages and Static content - node.js

var express = require("express");
var app = express();
var path = require("path");
app.use(express.static(__dirname + '/view'));
app.get('/dashboard',function(req,res){
res.sendFile((path.join(__dirname + '/dashboard.html'));
});
app.get('/index1',function(req,res){
res.sendFile((path.join(__dirname+'/index.html'));
});
app.get('/',function(req,res){
res.redirect('/login');
});
app.get('/login',function(req,res){
res.redirect((path.join(__dirname + '/login'));
});
app.listen(3000);
console.log("Running at Port 3000");
My Problem here is why do I need to check each time what user is requesting for?
Also, what if I have 100 html files in my directory do I need to check the each file through get method and then return the page through res.sendFile?

What #OrangeDog and #Clemens Himmer said are both true. However, the simplest way to serve all the files in a directory is already in your script:
app.use(express.static(__dirname + '/view'));
That will serve everything in your view directory if the name matches the URL, e.g. http://yoursite.com/index.html will resolve to the file at __dirname + '/view/index.html'.
In your example routes, however, you seem to be changing the URL path to no longer match the file location (for example, /login you want to resolve to '/login.html'). You could definitely write middleware to munge that and resolve the file based on a pattern, but at that point it's far simpler to use a purpose built web server (like nginx as previously suggested) which has URL rewrite features already baked in.

No, you don't have to list all your static files programatically. You can serve them dynamically by binding middleware to the server's root.
This is a small express.js script i've done, it's basically a really simple web server that serves anything and pretty HTML.
// This servers a file..
var serveFile = function(filePath, res){
var options = {
dotfiles: 'deny',
headers: {
'x-timestamp': Date.now(),
'x-sent': true
}
};
res.sendFile(filePath, options, function (err) {
if (err) {
console.log(err);
res.status(err.status).end();
}
});
};
// Serve web files
app.use("/", function (req, res, next) {
var filePath = (absoluteServePath + req.originalUrl).replace(/\//g,"\\");
var checkFilePath = function(filePath){
return new Promise(function(resolve, reject) {
fs.access(filePath, fs.F_OK, function(err) {
if(!err){
// If FILE / DIR exists check if file or DIR
if(fs.lstatSync(filePath).isDirectory() == true){
reject();
}
else{
resolve();
}
}else{
reject(err);
}
});
});
};
checkFilePath(filePath).then(function(){
serveFile(filePath,res);
},function(){
// Check if path ends with a slash
var endsWithSlash = filePath.substr(filePath.length - 1) == "\\";
// Check if a index.html exists in the path
var indexHTMLPath = filePath + ((endsWithSlash == true) ? "" : "\\") + "index.html";
checkFilePath(indexHTMLPath).then(function(){
serveFile(indexHTMLPath,res);
},function(){
// Check if .html for the path exists
var plusHTMLPath = filePath +".html";
checkFilePath(plusHTMLPath).then(function(){
serveFile(plusHTMLPath,res);
},function(){
// Nope, does not exist at all
next();
});
});
});
});

My Problem here is why do I need to check each time what user is requesting for?
How are you supposed to give the user what they requested if you don't check what that is?
What if I have 100 html files in my directory do I need to check the each file through get method and then return the page through res.sendFile?
If you mean do you need to declare a separate route for every file, then the answer is no. Express routes can be pattern-based, so you can define a route for e.g. a whole directory, then return the specific file that was requested: Simple static HTML server in Node.
This all leads on however to Node.JS not being a great choice for serving lots of static content. There are many security and other concerns you need to take care of, and it's just not as performant as it could be. You are likely to have a better time if you use an nginx or apache2 server to serve these files, forwarding dynamic requests to your Node server.
Node.js + Nginx - What now?

Related

How can I serve my Vuejs front end files from my node/express server?

Basically, I have two routes with express one for the home page and other for the admin page, but I cannot find a good documentation on how to combine Vuejs and Express, so I can serve at the same time both pages assuming that both have different UI's, so the components are not constructed the same.
To use vue-router and avoid running into 404 issues, your express.js has to have a fallback that serves the index.html. Here is a vue guide on how to do it https://router.vuejs.org/en/essentials/history-mode.html
To serve static files with expressjs you need to use the static middleware.
It accepts the directory name as the first argument. This directory shall contain all the static files to be served.
const express = require('express');
let app = express();
app.use(express.static('public')); // NAME OF THE DIRECTORY IS PUBLIC
const serverPort = 3000;
const respHttpOptions = {
root: `public/`,
dotfiles: 'deny',
headers: {
'dina-timestamp': Date.now(),
'my-xxx-header': true
}
};
app.get('/', (req, resp) => { // HANDLE THE REQUEST HERE
resp.sendFile('index.html', respHttpOptions, (err) => {
// SEND INDEX.HTML INSIDE PUBLIC DIRECTORY
if (!err)
console.log(sucL(`Served index.html`));
else
console.log(errL(`Failed to serve index.html ${err}`));
})
});
try {
app.listen(serverPort);
console.log(sucL(`Server started at ${serverPort}`));
} catch (e) {
console.log(errL(e));
}
There is no distinction for vuejs! You could have multiple directories inside the static directory.

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.

Node.js + Serve Static Files with RESTIFY

I have a multi-level collection of .html, .js, .png, .css, etc files in a site. A peek at my site hiearchy looks like the following:
index.html
child1
index.html
page1.html
page2.html
...
child2
grandchild1
index.html
grandchild2
index.html
index.html
page1.html
page2.html
resources
css
myTheme.css
img
logo.png
profile.png
js
jquery.js
...
...
I am migrating this to run under Node.js. I have been told I MUST use RESTIFY. Currently, I've written the following for my server:
var restify = require('restify');
var fs = require('fs');
var mime = require('mime');
var server = restify.createServer({
name: 'Demo',
version: '1.0.0'
});
server.use(restify.acceptParser(server.acceptable));
server.use(restify.queryParser());
server.use(restify.bodyParser());
server.get('/', loadStaticFile);
server.get('/echo/:name', function (req, res, next) {
res.send(req.params);
return next();
});
server.listen(2000, function () {
console.log('Server Started');
});
function loadStaticFile(req, res, next) {
var filePath = __dirname + getFileName(req);
console.log("Returning " + filePath);
fs.readFile(filePath, function(err, data) {
if (err) {
res.writeHead(500);
res.end("");
next(err);
return;
}
res.contentType = mime.lookup(filename);
res.writeHead(200);
res.end(data);
return next();
});
}
function getFileName(req) {
var filename = "";
if (req.url.indexOf("/") == (req.url.length-1)) {
filename = req.url + "index.html";
} else {
console.log("What Now?");
}
return filename;
}
With this code, I can successfully load index.html. However, my index.html file references some JavaScript, image files, and style sheets. I can see via Fiddler that that these files are being requested. However, in my node.js console window, I never see "Returing [js|css|png filename]". Its like my node.js web server returns index.html and that's it.
What am I doing wrong?
The latest versions of restify has builtin middleware serveStatic() middleware that will do this for you.
from a http://mcavage.me/node-restify/#Server-API
server.get(/\/docs\/public\/?.*/, restify.serveStatic({
directory: './public'
}));
for more detailed example:
http://mushfiq.me/2013/11/02/serving-static-files-using-restify/
Do any of your served files contain relative paths (say ../abc.js)?
You have to use path.resolve() to get the real path for fs.readFile().
Anyway there are a lot of pitfalls in serving files:
invalid url (400)
file not found (404)
escape sequence (url encoding)
fs.read() read files into memory (by #robertklep)
etc
You can use existing static file serving middleware.
I've been using Ecstatic, AFAIK it handles those issues properly.
Try
server.use(ecstatic({ root: __dirname + '/' }));
If that fails you can refer to this to stack Restify on top of Connect/Express.

expressjs: how to redirect to a static file in the middle of an handler?

I am using expressjs, I would like to do something like this:
app.post('/bla',function(req,res,next){
//some code
if(cond){
req.forward('staticFile.html');
}
});
As Vadim pointed out, you can use res.redirect to send a redirect to the client.
If you want to return a static file without returning to the client (as your comment suggested) then one option is to simply call sendfile after constructing with __dirname. You could factor the code below into a separate server redirect method. You also may want to log out the path to ensure it's what you expect.
filePath = __dirname + '/public/' + /* path to file here */;
if (path.existsSync(filePath))
{
res.sendfile(filePath);
}
else
{
res.statusCode = 404;
res.write('404 sorry not found');
res.end();
}
Here's the docs for reference: http://expressjs.com/api.html#res.sendfile
Is this method suitable for your needs?
app.post('/bla',function(req,res,next){
//some code
if(cond){
res.redirect('/staticFile.html');
}
});
Of course you need to use express/connect static middleware to get this sample work:
app.use(express.static(__dirname + '/path_to_static_root'));
UPDATE:
Also you can simple stream file content to response:
var fs = require('fs');
app.post('/bla',function(req,res,next){
//some code
if(cond){
var fileStream = fs.createReadStream('path_to_dir/staticFile.html');
fileStream.on('open', function () {
fileStream.pipe(res);
});
}
});
Sine express deprecated res.sendfile you should use res.sendFile instead.
Pay attention that sendFile expects a path relative to the current file location (not to the project's path like sendfile does). To give it the same behaviour as sendfile - just set root option pointing to the application root:
var path = require('path');
res.sendfile('./static/index.html', { root: path.dirname(require.main.filename) });
Find here the explanation concerning path.dirname(require.main.filename)
Based on #bryanmac's answer:
app.use("/my-rewrite", (req, res, next) => {
const indexFile = path.join(__dirname, "index.html");
// Check if file exists
fs.stat(indexFile, (err, stats) => {
if (err) {
// File does not exist or is not accessible.
// Proceed with other middlewares. If no other
// middleware exists, expressjs will return 404.
next();
return;
}
// Send file
res.sendFile(indexFile);
});
});
Since path.exists and path.existsSync don't exist anymore in Node.js v16.9.1, fs.stat is used.

Using routes in Express-js

So I'm starting to use Node.js. I saw the video with Ryan Dahl on Nodejs.org and heard he recommended Express-js for websites.
I downloaded the latest version of Express, and began to code. I have a fully fledged static view up on /, but as soon as I try sending parameters, I get errors like this:
Cannot GET /wiki
I tried following the guide on expressjs.com but the way one uses routes has changed in the latest version, which makes the guide unusable.
Guide:
app.get('/users/:id?', function(req, res, next){
var id = req.params.id;
if (id) {
// do something
} else {
next();
}
});
Generated by Express:
app.get('/', routes.index);
My problem arises when I try and add another route.
app.get('/wiki', routes.wiki_show);
I've tried a bunch of approaches, but I keep getting the Cannot GET /wiki (404) error.
routes/index.js looks like this:
exports.index = function(req, res) {
res.render('index', { title: 'Test', articles: articles, current_article: current_article, sections: sections })
};
The only thing I did there was add some parameters (arrays in the same file) and this i working. But when I copy the contents and change exports.index to exports.wiki or exports.wiki_show I still get the Cannot GET /wiki error.
Can anyone explain to me what I'm missing here? - Thanks.
So, after I created my question, I got this related list on the right with a similar issue: Organize routes in Node.js.
The answer in that post linked to the Express repo on GitHub and suggests to look at the 'route-separation' example.
This helped me change my code, and I now have it working. - Thanks for your comments.
My implementation ended up looking like this;
I require my routes in the app.js:
var express = require('express')
, site = require('./site')
, wiki = require('./wiki');
And I add my routes like this:
app.get('/', site.index);
app.get('/wiki/:id', wiki.show);
app.get('/wiki/:id/edit', wiki.edit);
I have two files called wiki.js and site.js in the root of my app, containing this:
exports.edit = function(req, res) {
var wiki_entry = req.params.id;
res.render('wiki/edit', {
title: 'Editing Wiki',
wiki: wiki_entry
})
}
The route-map express example matches url paths with objects which in turn matches http verbs with functions. This lays the routing out in a tree, which is concise and easy to read. The apps's entities are also written as objects with the functions as enclosed methods.
var express = require('../../lib/express')
, verbose = process.env.NODE_ENV != 'test'
, app = module.exports = express();
app.map = function(a, route){
route = route || '';
for (var key in a) {
switch (typeof a[key]) {
// { '/path': { ... }}
case 'object':
app.map(a[key], route + key);
break;
// get: function(){ ... }
case 'function':
if (verbose) console.log('%s %s', key, route);
app[key](route, a[key]);
break;
}
}
};
var users = {
list: function(req, res){
res.send('user list');
},
get: function(req, res){
res.send('user ' + req.params.uid);
},
del: function(req, res){
res.send('delete users');
}
};
var pets = {
list: function(req, res){
res.send('user ' + req.params.uid + '\'s pets');
},
del: function(req, res){
res.send('delete ' + req.params.uid + '\'s pet ' + req.params.pid);
}
};
app.map({
'/users': {
get: users.list,
del: users.del,
'/:uid': {
get: users.get,
'/pets': {
get: pets.list,
'/:pid': {
del: pets.del
}
}
}
}
});
app.listen(3000);
Seems that only index.js get loaded when you require("./routes") .
I used the following code in index.js to load the rest of the routes:
var fs = require('fs')
, path = require('path');
fs.readdirSync(__dirname).forEach(function(file){
var route_fname = __dirname + '/' + file;
var route_name = path.basename(route_fname, '.js');
if(route_name !== 'index' && route_name[0] !== "."){
exports[route_name] = require(route_fname)[route_name];
}
});
You could also organise them into modules. So it would be something like.
./
controllers
index.js
indexController.js
app.js
and then in the indexController.js of the controllers export your controllers.
//indexController.js
module.exports = function(){
//do some set up
var self = {
indexAction : function (req,res){
//do your thing
}
return self;
};
then in index.js of controllers dir
exports.indexController = require("./indexController");
and finally in app.js
var controllers = require("./controllers");
app.get("/",controllers.indexController().indexAction);
I think this approach allows for clearer seperation and also you can configure your controllers by passing perhaps a db connection in.
No one should ever have to keep writing app.use('/someRoute', require('someFile')) until it forms a heap of code.
It just doesn't make sense at all to be spending time invoking/defining routings. Even if you do need custom control, it's probably only for some of the time, and for the most bit you want to be able to just create a standard file structure of routings and have a module do it automatically.
Try Route Magic
As you scale your app, the routing invocations will start to form a giant heap of code that serves no purpose. You want to do just 2 lines of code to handle all the app.use routing invocations with Route Magic like this:
const magic = require('express-routemagic')
magic.use(app, __dirname, '[your route directory]')
For those you want to handle manually, just don't use pass the directory to Magic.

Resources