Serving static files with restify - node.js

I am learning to use Node.js. Currently, I have a folder structure that looks like the following:
index.html
server.js
client
index.html
subs
index.html
page.html
res
css
style.css
img
profile.png
js
page.js
jquery.min.js
server.js is my webserver code. I run this from a command-line using node server.js. The contents of that file are:
var restify = require('restify');
var server = restify.createServer({
name: 'Test App',
version: '1.0.0'
});
server.use(restify.acceptParser(server.acceptable));
server.use(restify.queryParser());
server.use(restify.bodyParser());
server.get('/echo/:name', function (req, res, next) {
res.send(req.params);
return next();
});
server.listen(2000, function () {
console.log('%s running on %s', server.name, server.url);
});
As you can see, this server relies on RESTIFY. I've been told I must use RESTIFY. However, I can't figure out how to serve static files. For instance, how do I server the *.html, *.css, *.png, and *.js files in my app?
Thank you!

From the documentation:
server.get(/\/docs\/public\/?.*/, restify.plugins.serveStatic({
directory: './public'
}));
But this will search files in the ./public/docs/public/ directory.
If you want to not append request path to it, use appendRequestPath: false option.
I prefer to use __dirname key here:
server.get(/\/public\/?.*/, restify.plugins.serveStatic({
directory: __dirname
}));
The value of __dirname is equal to script file directory path, which assumed to be also a folder, where is public directory.
And now we map all /public/.* urls to ./public/ directory.
Now also exists serveStaticFiles plugin:
server.get('/public/*', // don't forget the `/*`
restify.plugins.serveStaticFiles('./doc/v1')
); // GET /public/index.html -> ./doc/v1/index.html file

According to my current restify version (v5.2.0)
the serveStatic has been moved into plugins, so the code would be like this
server.get(
/\/(.*)?.*/,
restify.plugins.serveStatic({
directory: './static',
})
)
Syntax above will serve your static files on folder static. So you can get the static file like http://yoursite.com/awesome-photo.jpg
For some reason if you want to serve the static files under specific path like this http://yoursite.com/assets/awesome-photo.jpg for example.
The code should be refactored into this
server.get(
/\/assets\/(.*)?.*/,
restify.plugins.serveStatic({
directory: `${app_root}/static`,
appendRequestPath: false
})
)
The option appendRequestPath: false above means we dont include assets path into the file name

From Restify 7 the routes no longer take full regexes, so if you want /public/stylesheet.css to serve the file ./public/stylesheet.css, your code would now look like this:
server.get('/public/*', restify.plugins.serveStatic({
directory: __dirname,
}))
This is because Restify 7 has a new (potentially faster) routing back-end: find-my-way

this is how i'm serving static files in restify
server.get(/\/public\/docs\/?.*/, restify.plugins.serveStatic({
directory: __dirname,
default: 'index.html'
}));
public access path will be : example.com/public/docs/index.html

I came across this issue just recently, so while this may not help you it could help others who are having trouble with it.
When you declare Restify as const restify = require('restify');, the serveStatic method will be in the plugins object so using restify.serveStatic will quietly fail. The correct way to access the method is restify.plugins.serveStatic.
You can find the update docs here: http://restify.com/docs/plugins-api/#serve-static

server.get('/', function(req, res, next) {
fs.readFile(__dirname + '/index.html', function (err, data) {
if (err) {
next(err);
return;
}
res.setHeader('Content-Type', 'text/html');
res.writeHead(200);
res.end(data);
next();
});
});

Try this : Here view is a static resource directory name
server.get('/\/.*/', restify.plugins.serveStatic({
directory: __dirname + "/view/",
default: './home.html'
})
);

Related

Unable to send response using app.use in node js

code is used to set up server and calling a html page
const express =require('express')
const path=require('path')
const app=express()
const ppath=path.join(__dirname,'../public/index.htm')
app.use(express.static(ppath))
app.listen(3000,()=>
{**strong text**
console.log("HEy")
})
Try this.
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname, '..', 'public', 'index.htm'));
});
You pass express.static() a directory and it looks for requested files in that directory. You don't pass express.static() a path to a single file. That will not work.
If you actually want other static files in the same directory to be served, you could point express.static() at the parent directory.
Of, if you just want that one file served, then you just set up a route for that one file:
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname,'../public/index.htm'));
});
For an further help with express.static(), we also need to know exactly what the incoming URL is that you want to serve index.htm with.

Node.js Serving HTML pages and Static content

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?

Node.js: how to make default page to be sth. other than index.html

Originally, my node.js server goes to index.html by default.
Now I want to default to login.html so people can log in first.
My code is in .../server/server.js, while client page are in .../client/login.html, index.html, etc.
Now I modified server.js to be like this:
app.get('/', function(req, res)
{
res.sendfile(path.resolve('../client/login.html'));
});
After restart server.js, the webpage is still pointing to index.html by default. What am I missing?
If you're running ExpressJS on top of Nodejs, you can serve the files statically using the static method. The first parameter is the directory and the second allows you to specify the default file.
app.use(express.static('../client/', {index: 'login.html'}))
http://expressjs.com/guide/using-middleware.html#middleware.built-in
For your specific example, you can modify the sendFile to include the root with the second parameter:
res.status(200).sendFile('login.html', { root: path.join(__dirname, '../client/') });
If you also have a router that's handling getting an index page for you and you want to render a handlebar page or do something else instead, you can put anything in the index option and it will ignore it if not found in your static asset folder:
app.use(
express.static(
path.resolve(__dirname, "../Client/assets/"),
{index: "userouterinstead"}
)
)
app.use("/", route_configs)
app.get("*", (req, res, next) => {
res.sendFile(
path.resolve( __dirname, "../Client/assets/index.html" )
)
})

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.

Any way to serve static html files from express without the extension?

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!');
})

Resources