简体   繁体   中英

nodejs web root

I was under the impression that when you run a nodejs webserver the root of the web is the folder containing the js file implementing the webserver. So if you have C:\\foo\\server.js and you run it, then "/" refers to C:\\foo and "/index.htm" maps to C:\\foo\\index.htm

I have a file server.js with a sibling file default.htm, but when I try to load the contents of /default.htm the file is not found. An absolute file path works.

Where is "/" and what controls this?


Working up a repro I simplified it to this:

var fs = require('fs');
var body = fs.readFileSync('/default.htm');

and noticed it's looking for this

Error: ENOENT, no such file or directory 'C:\default.htm'

So "/" maps to C:\\

Is there a way to control the mapping of the web root?


I notice that relative paths do work. So

var fs = require('fs');
var body = fs.readFileSync('default.htm');

succeeds.

I believe my confusion arose from the coincidental placement of my original experiment's project files at the root of a drive. This allowed references to /default.htm to resolve correctly; it was only when I moved things into a folder to place them under source control that this issue was revealed.

I will certainly look into express, but you haven't answered my question: is it possible to remap the web root and if so how?

As a matter of interest this is server.js as it currently stands

var http = require('http');
var fs = require('fs');
var sys = require('sys');
var formidable = require('formidable');
var util = require('util');
var URL = require('url');
var QueryString = require('querystring');
var mimeMap = { htm : "text/html", css : "text/css", json : "application/json" };
http.createServer(function (request, response) {
  var body, token, value, mimeType;
  var url = URL.parse(request.url);
  var path = url.pathname;
  var params = QueryString.parse(url.query);  
  console.log(request.method + " " + path);  
  switch (path) {
    case "/getsettings":
      try {
        mimeType = "application/json";
        body = fs.readFileSync("dummy.json"); //mock db 
      } catch(exception) {
        console.log(exception.text);
        body = exception;
      }
      break;  
    case "/setsettings":
      mimeType = "application/json";
      body="{}";
      console.log(params);
      break;  
    case "/": 
      path = "default.htm";
    default:
      try { 
        mimeType = mimeMap[path.substring(path.lastIndexOf('.') + 1)];
        if (mimeType) {
         body = fs.readFileSync(path);
        } else {
          mimeType = "text/html";
          body = "<h1>Error</h1><body>Could not resolve mime type from file extension</body>";
        }
      } catch (exception) {
        mimeType = "text/html";
        body = "<h1>404 - not found</h1>" + exception.toString();
      }
      break;
  }
  response.writeHead(200, {'Content-Type': mimeType});
  response.writeHead(200, {'Cache-Control': 'no-cache'});
  response.writeHead(200, {'Pragma': 'no-cache'});
  response.end(body);  
}).listen(8124);
console.log('Server running at http://127.0.0.1:8124/');

I'm not completely certain what you mean by "routes" but I suspect that setsettings and getsettings are the sort of thing you meant, correct me if I'm wrong.


Nodejs does not appear to support arbitrary mapping of the web root.

All that is required is to prepend absolute web paths with a period prior to using them in the file system:

var URL = require('url');
var url = URL.parse(request.url);
var path = url.pathname;
if (path[0] == '/')
  path = '.' + path;

While you're correct that the root of the server is the current working directory Node.js won't do a direct pass-through to the files on your file system, that could be a bit of a security risk after all.

Instead you need to provide it with routes that then in turn provide content for the request being made.

A simple server like

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(1337, '127.0.0.1');

Will just capture any request and respond in the same way (but doesn't read the file system).

Now if you want to serve out file contents you need to specify some way to read that file into the response stream, this can be done a few ways:

  1. You can use the fs API to find the file on disk, read its contents into memory and then pipe them out to the response. This is a pretty tedious approach, especially when you start getting a larger number of files, but it does allow you very direct control over what's happening in your application
  2. You can use a middleware server like express.js , which IMO is a much better approach to do what you're wanting to do. There's plenty of questions and answers on using Express here on StackOverflow, this is a good example of a static server which is what you talk about

Edit

With the clarification of the question the reason:

var body = fs.readFileSync('/default.htm');

Results in thinking the file is at C:\\default.htm is because you're using an absolute path not a relative path. If you had:

var body = fs.readFileSync('./default.htm');

It would then know that you want to operate relative to the current working directory. / is from the root of the partition and ./ is from the current working directory .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM