Node.js quick file server (static files over HTTP)

623,053

Solution 1

A good "ready-to-use tool" option could be http-server:

npm install http-server -g

To use it:

cd D:\Folder
http-server

Or, like this:

http-server D:\Folder

Check it out: https://github.com/nodeapps/http-server

Solution 2

If you do not want to use ready tool, you can use the code below, as demonstrated by me at https://developer.mozilla.org/en-US/docs/Node_server_without_framework:

var http = require('http');
var fs = require('fs');
var path = require('path');

http.createServer(function (request, response) {
    console.log('request starting...');

    var filePath = '.' + request.url;
    if (filePath == './')
        filePath = './index.html';

    var extname = path.extname(filePath);
    var contentType = 'text/html';
    switch (extname) {
        case '.js':
            contentType = 'text/javascript';
            break;
        case '.css':
            contentType = 'text/css';
            break;
        case '.json':
            contentType = 'application/json';
            break;
        case '.png':
            contentType = 'image/png';
            break;      
        case '.jpg':
            contentType = 'image/jpg';
            break;
        case '.wav':
            contentType = 'audio/wav';
            break;
    }

    fs.readFile(filePath, function(error, content) {
        if (error) {
            if(error.code == 'ENOENT'){
                fs.readFile('./404.html', function(error, content) {
                    response.writeHead(200, { 'Content-Type': contentType });
                    response.end(content, 'utf-8');
                });
            }
            else {
                response.writeHead(500);
                response.end('Sorry, check with the site admin for error: '+error.code+' ..\n');
                response.end(); 
            }
        }
        else {
            response.writeHead(200, { 'Content-Type': contentType });
            response.end(content, 'utf-8');
        }
    });

}).listen(8125);
console.log('Server running at http://127.0.0.1:8125/');

UPDATE If you need to access your server from external demand/file, you need to overcome the CORS, in your node.js file by writing the below, as I mentioned in a previous answer here

// Website you wish to allow to connect
response.setHeader('Access-Control-Allow-Origin', '*');

// Request methods you wish to allow
response.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');

// Request headers you wish to allow
response.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');

// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
response.setHeader('Access-Control-Allow-Credentials', true);

UPDATE

As Adrian mentioned, in the comments, he wrote an ES6 code with full explanation here, I just re-posting his code below, in case the code gone from the original site for any reason:

const http = require('http');
const url = require('url');
const fs = require('fs');
const path = require('path');
const port = process.argv[2] || 9000;

http.createServer(function (req, res) {
  console.log(`${req.method} ${req.url}`);

  // parse URL
  const parsedUrl = url.parse(req.url);
  // extract URL path
  let pathname = `.${parsedUrl.pathname}`;
  // based on the URL path, extract the file extension. e.g. .js, .doc, ...
  const ext = path.parse(pathname).ext;
  // maps file extension to MIME typere
  const map = {
    '.ico': 'image/x-icon',
    '.html': 'text/html',
    '.js': 'text/javascript',
    '.json': 'application/json',
    '.css': 'text/css',
    '.png': 'image/png',
    '.jpg': 'image/jpeg',
    '.wav': 'audio/wav',
    '.mp3': 'audio/mpeg',
    '.svg': 'image/svg+xml',
    '.pdf': 'application/pdf',
    '.doc': 'application/msword'
  };

  fs.exists(pathname, function (exist) {
    if(!exist) {
      // if the file is not found, return 404
      res.statusCode = 404;
      res.end(`File ${pathname} not found!`);
      return;
    }

    // if is a directory search for index file matching the extension
    if (fs.statSync(pathname).isDirectory()) pathname += '/index' + ext;

    // read file from file system
    fs.readFile(pathname, function(err, data){
      if(err){
        res.statusCode = 500;
        res.end(`Error getting the file: ${err}.`);
      } else {
        // if the file is found, set Content-type and send data
        res.setHeader('Content-type', map[ext] || 'text/plain' );
        res.end(data);
      }
    });
  });


}).listen(parseInt(port));

console.log(`Server listening on port ${port}`);

Solution 3

For people wanting a server runnable from within NodeJS script:

You can use expressjs/serve-static which replaces connect.static (which is no longer available as of connect 3):

myapp.js:

var http = require('http');

var finalhandler = require('finalhandler');
var serveStatic = require('serve-static');

var serve = serveStatic("./");

var server = http.createServer(function(req, res) {
  var done = finalhandler(req, res);
  serve(req, res, done);
});

server.listen(8000);

and then from command line:

  • $ npm install finalhandler serve-static
  • $ node myapp.js

Solution 4

I know it's not Node, but I've used Python's SimpleHTTPServer:

python -m SimpleHTTPServer [port]

It works well and comes with Python.

Solution 5

From [email protected], npm started installing a new binary alongside the usual npm called npx. So now, one liners to create static http server from current directory:

npx serve

or

npx http-server
Share:
623,053
Paul Verest
Author by

Paul Verest

Java Developer, Architect, Team Leader; Agile Coach, Tech Manager Authoring Nodeclipse, Anide.js, Enide Organizing http://szjug.github.io/ Building up JVMs, Spring.io and Node.js User Groups (Java, Groovy, Scala, Android, JavaScript)

Updated on July 08, 2022

Comments

  • Paul Verest
    Paul Verest almost 2 years

    Is there Node.js ready-to-use tool (installed with npm), that would help me expose folder content as file server over HTTP.

    Example, if I have

    D:\Folder\file.zip
    D:\Folder\file2.html
    D:\Folder\folder\file-in-folder.jpg
    

    Then starting in D:\Folder\ node node-file-server.js I could access file via

    http://hostname/file.zip
    http://hostname/file2.html
    http://hostname/folder/file-in-folder.jpg
    

    Why is my node static file server dropping requests? reference some mystical

    standard node.js static file server

    If there's no such tool, what framework should I use?

    Related: Basic static file server in NodeJS

  • Paul Verest
    Paul Verest about 11 years
    Can I $ npm install -g express ; them $ express ?
  • Tim Heap
    Tim Heap about 11 years
    I built that server. That file server was built against a very old version of Node, hence why it does not work any more. I do not have the time right now to fix it up. I suggest using the answer by @Oleg above. It can be easily bundled into a small node executable, and is essentially what mine did anyway.
  • Paul Verest
    Paul Verest about 11 years
    Thank you Tim, very professional response. I wouldn't delete code though, but update readme.
  • jakub.g
    jakub.g almost 10 years
    This does not work any longer as of connect 3 as it doesn't expose connect.static; see my answer below for a replacement
  • Oleg
    Oleg almost 10 years
    I believe that it is still bundled with express by default, but indeed exists now in a separate requireable module "serve-static".
  • Lee Jenkins
    Lee Jenkins over 9 years
    FYI This did not work for me. I installed filehandler using npm install filehandler and the package is listed in the node_modules directory. But when I run myapp.js node throws an error, saying Error: cannot find module filehandler. If I comment out the require ststment to load filehandler the app loads serve-static just fine, so it looks like there's something wrong with the filhandler package. Today is December 12, 2014, so maybe the package has changed since this answer was posted?
  • jakub.g
    jakub.g over 9 years
    It's final handler not file
  • jakub.g
    jakub.g over 9 years
    Python3 equivalent: python -m http.server [port] (the mentioned one is for Python2)
  • Sam Berry
    Sam Berry about 9 years
    This is awesome. I needed to specify an address bc for some reason the default 0.0.0.0 wasn't cooperating w my dev environment. http-server -a localhost got er dun.
  • Muhammad Umer
    Muhammad Umer almost 9 years
    i use http-server -a localhost -p 80
  • bigtunacan
    bigtunacan almost 9 years
    Yeah; it's slightly weird in that it doesn't automap localhost, but you can access from 0.0.0.0:8080
  • Thomas Hunter II
    Thomas Hunter II over 8 years
    Surely, response.writeHead(200 should be response.writeHead(404 ;)
  • JsAndDotNet
    JsAndDotNet over 8 years
    Update - My answer works, but I now use @Matt Self's answer of using http-server. It seems to work well.
  • Dheeraj Sam
    Dheeraj Sam over 8 years
    Thank you so much! That was simple! ;)
  • garryp
    garryp over 8 years
    Doesn't get much simpler than this
  • Bill
    Bill over 8 years
    Correct me if I am wrong, but if you get 404 it still writes the content type as if it was whatever was requested, instead of text/html?
  • Abhinav Gauniyal
    Abhinav Gauniyal over 8 years
    You should add some explanation alog with this code.
  • Rolf
    Rolf over 8 years
    Would that code not allow going up the file tree by doing something like 127.0.0.1/../../../etc/passwd ? I see no checks against that.
  • Zimy
    Zimy about 8 years
    Python fails for me when it is about serving large files like OS images. Fedora 23
  • szhuravel
    szhuravel about 8 years
    http-server works well for me on Windows. Btw, http-server -o opens my default browser with index page on 127.0.0.1:8080. Also there is a bunch of other useful parameters. For quick tests it's really the best tool.
  • Adrian
    Adrian almost 8 years
    If anyone interested in the ES6+ version, I created a static file server that handles MIME types: gist.github.com/amejiarosario/53afae82e18db30dadc9bc39035778‌​e5
  • Hasan A Yousef
    Hasan A Yousef almost 8 years
    @Adrian, well done, thanks for your added value comment.
  • Nick F
    Nick F over 7 years
    The advantage of using Browsersync rather than other static servers is that it live updates the page whenever the files specified by the --files flag change (nb. you don't need to specify ./* - only the ones that you want Browsersync to actively watch for updates, eg. css/*.css)
  • Nick F
    Nick F over 7 years
    It's worth checking browser-sync too, which can do more-or-less the same thing but with the added bonus of live-updating when files are modified.
  • Wei Xia
    Wei Xia over 7 years
    Hi, I can run it correctly, but it shows Cannot GET /. I use AWS EC2 to run the server.
  • pasx
    pasx over 7 years
    @Wei Hi, late answer. From what I can see from a quick Google search it looks like your directory structure might be wrong. There must be an index.html file in the location you are targeting. Setting up the above example to run should take 5 minutes and I double checked that it works as is. From there you can tweak the path to suit your directory structure and check that the server still finds the files it needs to server.
  • klimat
    klimat over 7 years
    another advantage of this solution is, files aren't cached, so you don't need to restart a process when making changes in code.
  • dennis
    dennis about 7 years
    And on PHP: php -S localhost:8000
  • Adrian Lynch
    Adrian Lynch about 7 years
    I use this to quickly serve content from a folder all the time.
  • Giorgi Moniava
    Giorgi Moniava about 7 years
    in your example you have: response.end(content, 'utf-8'); , how it will send binary file if you set utf8 as encoding?
  • Daniel F
    Daniel F about 7 years
    --cors to send Access-Control-Allow-Origin:* along with the response headers (ie when serving a json file)
  • Eduard Bondarenko
    Eduard Bondarenko about 7 years
    Don't use the sync version. Instread create pipe to res from readStream.
  • AceMark
    AceMark almost 7 years
    a very good tool. helped me out right now. kudos to @indexzero
  • Seph Reed
    Seph Reed almost 7 years
    @Adrian This code is very awesome, but I have found a way to get root access with it. The solution is to limit the amount of leading periods on the filename to one so you can't do ../../etc/password stuff. gist.github.com/amejiarosario/53afae82e18db30dadc9bc39035778‌​e5
  • Seph Reed
    Seph Reed almost 7 years
    pathname = pathname.replace(/^(\.)+/, '.');
  • sdgfsdh
    sdgfsdh almost 7 years
    path.join(__dirname, 'public') is more cross-platform.
  • Qwerty
    Qwerty over 6 years
    I followed your steps, but my express does not have bin folder
  • Qwerty
    Qwerty over 6 years
    This also watches for changes and provides live reload.
  • singhpradeep
    singhpradeep over 6 years
    awesome dude... simple and plain answer without third party API to read and send static contents to client.
  • abentan
    abentan over 6 years
    Excellent quick server version! Thanks. I am using font-awesome and got some problems, 404, because the filepath include a query: localhost:8484/fonts/fontawesome-webfont.woff2?v=4.3.0 and the extension can't be recognized. Can use this to fix it, add: var url = require('url'); and replace the filePath with: var q = url.parse(request.url, true); var filePath = '.' + q.pathname; to retrieve the pathname without the query.
  • Chirag Parekh
    Chirag Parekh over 6 years
    Thanks. This is the really awesome solution.
  • Colin
    Colin over 6 years
    I found useful live-server for development it watches changes.
  • Coli
    Coli about 6 years
    Because exists is deprecated, you should use fs.access instead. @HasanAYousef
  • The Anh Nguyen
    The Anh Nguyen about 6 years
    Very nice! But for me, I need extra fuction like Basic Authentication. It will be awesome
  • Faris Rayhan
    Faris Rayhan almost 6 years
    This is absolutely awesome tool. Damn it :)
  • collapsar
    collapsar almost 6 years
    Best answer if you need a quick & dirty one-time one trick pony.
  • Mike McKay
    Mike McKay over 5 years
    npx http-server - npx turns it into a one-liner that downloads the necessary files and runs it.
  • William Jones
    William Jones over 5 years
    It just downloads the file for me.
  • Hamzeen Hameem
    Hamzeen Hameem over 5 years
    try this if you haven't installed http-server globally: npx http-server -a 0.0.0.0 -p 80 this way your server will be accessible by all the machines that share the same network as yours.
  • derickito
    derickito about 5 years
    You realize that npm is the node package manager so you're in fact using the NodeJS stuff
  • Diego Mendes
    Diego Mendes about 5 years
    I do, What I meant as "NodeJS stuff" was using NodeJS and express to serve the files like most answers suggested. Serve is an independent executable, NPM is used just to install it, you could just download it directly.
  • Joseph Cho
    Joseph Cho about 5 years
    If you want to avoid using index.html as part of your address just add if (req.url === '/') req.url = '/index.html'; right after res.writeHead(200);.
  • Justin Meiners
    Justin Meiners about 5 years
    @EduardBondarenko is right. const stream = fs.createReadStream(...); stream.pipe(res); is all you need
  • Ashkan Hovold
    Ashkan Hovold over 4 years
    This is beautiful! Got my static website running with a single command instead of having to install some extra web server!
  • FrenkyB
    FrenkyB over 4 years
    Is this also possible with https-server ?
  • akauppi
    akauppi over 3 years
    For simple development tasks, I've found your approach to be better than bringing in some 'out of the box' service. No added dependencies, ability to do unorthodox things (today, I needed to do routing, and servers don't usually do it).
  • arthurDent
    arthurDent over 3 years
    This is a C++ Server which has no relation to a Node.js Solution. Also the name is misleading in this Thread because it shares it's name with a popular MongoDB Layer for Node.js.
  • Blaise
    Blaise about 3 years
    NodeJs equivalent npx http-server [-p 8000] [<dir>]
  • rahul
    rahul about 3 years
    I cannot download multiple files simultaneously with python server. Any work around for that?
  • Spongebob Comrade
    Spongebob Comrade about 2 years
    so cool .......... :D
  • Paflow
    Paflow about 2 years
    Lot's of error in this. Variable names are not consistend (response, res etc).