题 使用node.js作为简单的Web服务器


我想运行一个非常简单的HTTP服务器。每个GET请求 example.com 应得 index.html 服务于它但作为常规HTML页面(即,与您阅读普通网页时相同的体验)。

使用下面的代码,我可以阅读的内容 index.html。我如何服务 index.html 作为常规网页?

var http = require('http');
var fs = require('fs');
var index = fs.readFileSync('index.html');

http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end(index);
}).listen(9615);

下面的一个建议很复杂,需要我写一个 get 我要使用的每个资源(CSS,JavaScript,图像)文件的行。

如何使用一些图像,CSS和JavaScript提供单个HTML页面?


937
2018-05-21 20:44


起源


看看npm模块“connect”。它提供了这样的基本功能,是许多设置和其他包的基础。 - Mörre
您应该将解决方案作为答案并将其标记为正确。 - graham.reeds
我能够找到Eric B. Sowell所说的完美解决方案 从节点js提供静态文件。阅读整篇文章。强烈推荐。 - idophir
看看我写的一个名为Cachemere的模块。它还会自动缓存您的所有资源。 github.com/topcloud/cachemere - Jon
本地Web服务器 是一个很好的例子 - Lloyd


答案:


您可以使用  和 ServeStatic 与Node.js为此:

  1. 使用NPM安装connect和serve-static

    $ npm install connect serve-static
    
  2. 使用此内容创建server.js文件:

    var connect = require('connect');
    var serveStatic = require('serve-static');
    connect().use(serveStatic(__dirname)).listen(8080, function(){
        console.log('Server running on 8080...');
    });
    
  3. 使用Node.js运行

    $ node server.js
    

你现在可以去 http://localhost:8080/yourfile.html


862
2017-12-08 08:09



出于教育原因,我的想法是不使用现有的库,但我认为使用Express比其低级版本Connect更好。 - idophir
提供静态文件的Express部分只是Connect,所以我没有看到使用Express来提供静态文件的原因。但是,是的,Express也会做这个工作。 - Gian Marco Gherardi
很好的建议。上述步骤非常适合我的目的。感谢Gian,这是Express的链接,它显示它是建立在Connect上的, expressjs.com 以下是如何使用Express: expressjs.com/guide.html - Jack Spykes
不适合我,结果不能GET /test.html。我应该用目录名替换__dirname吗? - Timo
现在,connect已更改为版本3.因此,必须使用serve-static作为miqid描述。我发布了另一个答案,其中包含connect v3的完整代码。 - tomet


最简单的Node.js服务器就是:

$ npm install http-server -g

现在,您可以通过以下命令运行服务器:

$ cd MyApp

$ http-server

如果您使用的是NPM 5.2.0或更高版本,则可以使用 http-server 没有安装它 npx。建议不要在生产中使用它,但这是快速获取在localhost上运行的服务器的好方法。

$ npx http-server

或者,您可以尝试此操作,这将打开您的Web浏览器并启用CORS请求:

$ http-server -o --cors

有关更多选项,请查看 的文件 http-server 在GitHub上,或运行:

$ http-server --help

很多其他不错的功能和对NodeJitsu的脑死亡简单部署。

功能分叉

当然,您可以使用自己的分叉轻松实现功能。您可能会发现它已经在此项目的现有800多个分支中的一个中完成:

轻型服务器:自动刷新替代方案

一个不错的选择 http-server 是 light-server。它支持文件监视和自动刷新以及许多其他功能。

$ npm install -g light-server 
$ light-server

在Windows资源管理器中添加到目录上下文菜单

 reg.exe add HKCR\Directory\shell\LightServer\command /ve /t REG_EXPAND_SZ /f /d "\"C:\nodejs\light-server.cmd\" \"-s\" \"%V\""

简单的JSON REST服务器

如果您需要为原型项目创建一个简单的REST服务器 JSON-服务器 可能就是你要找的东西。

自动刷新编辑器

大多数网页编辑器和IDE工具现在都包含一个Web服务器,它将监视您的源文件并在更改时自动刷新您的网页。

开源 文本编辑器 括号 还包括NodeJS静态Web服务器。只需在Brackets中打开任何HTML文件,按“实时预览“它启动一个静态服务器并在页面上打开浏览器。浏览器将在编辑和保存HTML文件时自动刷新。这在测试自适应网站时特别有用。在多个浏览器/窗口大小上打开HTML页面保存您的HTML页面并立即查看您的自适应内容是否正常工作 所有 自动刷新。

PhoneGap开发人员

如果你正在编码 混合移动应用,你可能有兴趣知道 PhoneGap的团队采用了这种自动更新概念 PhoneGap应用程序。这是一个通用的移动应用程序,可以在开发期间从服务器加载HTML5文件。这是一个非常流畅的技巧,因为现在你可以跳过混合移动应用程序开发周期中的慢速编译/部署步骤,如果你要更改JS / CSS / HTML文件 - 这是你大部分时间都在做的事情。它们还提供静态NodeJS Web服务器(运行 phonegap serve)检测文件更改。

PhoneGap + Sencha Touch开发者

我现在已经为Sencha Touch和jQuery Mobile开发人员广泛调整了PhoneGap静态服务器和PhoneGap开发者应用程序。看看吧 Sencha Touch Live。支持--qr QR代码和--localtunnel,它将您的静态服务器从您的台式计算机代理到防火墙外的URL!吨的用途。大规模加速混合移动设备。

Cordova + Ionic框架开发人员

本地服务器和自动刷新功能被烘焙到 ionic 工具。赶紧跑 ionic serve 从您的应用程序文件夹更好...... ionic serve --lab 查看iOS和Android的自动刷新并排视图。


831
2018-04-17 01:21



npm install live-server -g  如果你想要相同的东西,但在检测到文件更改时自动重新加载 - Joe
一点点“陷阱” - 。 http-server默认为0.0.0.0提供站点服务。因此,您必须指定一个IP地址,以使其作为本地测试服务器正常工作: http-server -a localhost - JESii
是的... 0.0.0.0将使其绑定到所有IP网络设备(WiFi,电缆,蓝牙)的所有IP,这在任何公共网络上都是一个坏主意,因为您可能会被黑客入侵。如果您只是想在安全的防火墙网络中演示您的应用程序以显示其他人或将其连接到同一网络上的移动设备,那就不是那么糟糕了。 - Tony O'Hagan
真有用的小工具。我的服务器上运行了很多Node应用程序,所以我添加了一个“-p”选项来选择8080以外的端口。例如:nohup http-server -p 60080&(在后台启动它,让你断开连接shell会话。)你应该确保端口对世界是开放的,例如:iptables -I INPUT 1 -p tcp --dport 60090 -j ACCEPT(在许多Linux系统上) - Blisterpeanuts


看看这个 要旨。我在这里复制它以供参考,但要点已经定期更新。

Node.JS静态文件Web服务器。将它放在您的路径中以启动任何目录中的服务器,获取可选的端口参数。

var http = require("http"),
    url = require("url"),
    path = require("path"),
    fs = require("fs"),
    port = process.argv[2] || 8888;

http.createServer(function(request, response) {

  var uri = url.parse(request.url).pathname
    , filename = path.join(process.cwd(), uri);

  fs.exists(filename, function(exists) {
    if(!exists) {
      response.writeHead(404, {"Content-Type": "text/plain"});
      response.write("404 Not Found\n");
      response.end();
      return;
    }

    if (fs.statSync(filename).isDirectory()) filename += '/index.html';

    fs.readFile(filename, "binary", function(err, file) {
      if(err) {        
        response.writeHead(500, {"Content-Type": "text/plain"});
        response.write(err + "\n");
        response.end();
        return;
      }

      response.writeHead(200);
      response.write(file, "binary");
      response.end();
    });
  });
}).listen(parseInt(port, 10));

console.log("Static file server running at\n  => http://localhost:" + port + "/\nCTRL + C to shutdown");

更新

要点确实处理css和js文件。我自己用过它。在“二进制”模式下使用读/写不是问题。这只意味着文件不会被文件库解释为文本,并且与响应中返回的内容类型无关。

您的代码的问题是您总是返回内容类型的“text / plain”。上面的代码不会返回任何内容类型,但如果您只是将它用于HTML,CSS和JS,浏览器可以推断出这些内容就好了。 没有内容类型比错误的更好。

通常,内容类型是Web服务器的配置。如果这不能解决,我很抱歉 你的 问题,但它作为一个简单的开发服务器对我有用,并认为它可能会帮助其他人。如果确实需要在响应中使用正确的内容类型,则需要将其明确定义为joeytwiddle,或者使用具有合理默认值的Connect之类的库。关于这一点的好处是它简单且独立(没有依赖)。

但我确实感觉到了你的问题。所以这是组合的解决方案。

var http = require("http"),
    url = require("url"),
    path = require("path"),
    fs = require("fs")
    port = process.argv[2] || 8888;

http.createServer(function(request, response) {

  var uri = url.parse(request.url).pathname
    , filename = path.join(process.cwd(), uri);

  var contentTypesByExtension = {
    '.html': "text/html",
    '.css':  "text/css",
    '.js':   "text/javascript"
  };

  fs.exists(filename, function(exists) {
    if(!exists) {
      response.writeHead(404, {"Content-Type": "text/plain"});
      response.write("404 Not Found\n");
      response.end();
      return;
    }

    if (fs.statSync(filename).isDirectory()) filename += '/index.html';

    fs.readFile(filename, "binary", function(err, file) {
      if(err) {        
        response.writeHead(500, {"Content-Type": "text/plain"});
        response.write(err + "\n");
        response.end();
        return;
      }

      var headers = {};
      var contentType = contentTypesByExtension[path.extname(filename)];
      if (contentType) headers["Content-Type"] = contentType;
      response.writeHead(200, headers);
      response.write(file, "binary");
      response.end();
    });
  });
}).listen(parseInt(port, 10));

console.log("Static file server running at\n  => http://localhost:" + port + "/\nCTRL + C to shutdown");

147
2017-11-29 21:46



这并没有真正解决“问题”。您将index.html作为二进制文件返回,并且不处理css和js。 - idophir
它确实处理css和js。它不会将index.html作为二进制文件返回。它只是以任何格式从磁盘上复制数据。有关更多说明,请参阅更新。 - Jonathan Tran
代码有一个问题,它区分大小写,在某些文件的unix上,它给出了404 - Pradeep
请注意,“path.exists和path.existsSync现已弃用。请使用fs.exists和fs.existsSync。” stackoverflow.com/a/5008295/259 - David Sykes
注意 fs.exists() 现在也弃用了。抓住错误 fs.stat() 而不是创造一个竞争条件。 - Matt


你不需要快递。你不需要连接。 Node.js确实是http NATIVELY。您需要做的就是根据请求返回一个文件:

var http = require('http')
var url = require('url')
var fs = require('fs')

http.createServer(function (request, response) {
    var requestUrl = url.parse(request.url)    
    response.writeHead(200)
    fs.createReadStream(requestUrl.pathname).pipe(response)  // do NOT use fs's sync methods ANYWHERE on production (e.g readFileSync) 
}).listen(9615)    

一个更完整的示例,可确保请求无法访问基目录下的文件,并进行正确的错误处理:

var http = require('http')
var url = require('url')
var fs = require('fs')
var path = require('path')
var baseDirectory = __dirname   // or whatever base directory you want

var port = 9615

http.createServer(function (request, response) {
    try {
        var requestUrl = url.parse(request.url)

        // need to use path.normalize so people can't access directories underneath baseDirectory
        var fsPath = baseDirectory+path.normalize(requestUrl.pathname)

        var fileStream = fs.createReadStream(fsPath)
        fileStream.pipe(response)
        fileStream.on('open', function() {
             response.writeHead(200)
        })
        fileStream.on('error',function(e) {
             response.writeHead(404)     // assume the file doesn't exist
             response.end()
        })
   } catch(e) {
        response.writeHead(500)
        response.end()     // end the response so browsers don't hang
        console.log(e.stack)
   }
}).listen(port)

console.log("listening on port "+port)

75
2017-10-14 06:59



如果我没有弄错,这个解决方案不会处理编码类型,因此对HTML页面和图像的请求将获得相同的编码。不是吗? - idophir
@idophir大多数情况下编码并不重要,浏览器根据使用的html标签或其他信息推断它,或者他们猜得很好。像上面提到的那样,没有MIME类型比错误类型更好。你当然可以使用类似于node-mime的东西来找出mime类型的文件,但完全符合Web的http服务器不在这个问题的范围内。 - B T
@BT所以继续运行这个你会做的事情 nohup node thisfile.js  还是有更好的方法? - Rooster
@Rooster发现了一些名声的守护者 github.com/Unitech/pm2 - Travelling Man
我最喜欢这个答案,但有两个问题:1)当它应该返回404时返回200;修复我在'open'回调中调用writeHead(200)。 2)如果有错误,插座保持打开状态;修复我在'错误'回调中调用response.destroy()。 - Paul Brannan


我认为你现在缺少的那部分是你发送的:

Content-Type: text/plain

如果您希望Web浏览器呈现HTML,则应将其更改为:

Content-Type: text/html

64
2018-05-21 21:11



感谢您的快速回复。页面现在加载但没有CSS。如何加载CSS和JS的标准html页面? - idophir
您需要开始扩展该服务器。现在它只知道如何提供index.html - 你需要教它如何使用自己适当的MIME类型提供foo.css和foo.js。 - clee
如果您不想提供静态文件,可以将css放入 <style> 标签。 - Keith


Step1(在命令提示符内部[我希望你cd到你的文件夹]): npm install express

第2步:创建文件server.js

var fs = require("fs");
var host = "127.0.0.1";
var port = 1337;
var express = require("express");

var app = express();
app.use(express.static(__dirname + "/public")); //use static files in ROOT/public folder

app.get("/", function(request, response){ //root dir
    response.send("Hello!!");
});

app.listen(port, host);

请注意,您也应该添加WATCHFILE(或使用nodemon)。以上代码仅适用于简单的连接服务器。

第3步: node server.js 要么 nodemon server.js

如果您只想要主机简单的HTTP服务器,现在有更简单的方法。 npm install -g http-server

并打开我们的目录并输入 http-server

https://www.npmjs.org/package/http-server


43
2018-02-24 14:44



正是我需要的,thx - Stepan Suvorov
@STEEL,有没有办法自动启动节点服务器。我的意思是没有去目录路径,然后键入nodeserver然后它只会启动。我想像IIS一样启动节点服务器。你能告诉我吗 - Vinoth
@Vinoth是的,有很多方法。什么是你的确切目的或目标,我可以帮助你 - STEEL
@steel我想自动启动服务器而不在命令promt中提供节点服务器。这是我的要求是否有可能告诉我一些例子 - Vinoth
您需要使用像ThoughtWorks GO这样的工具,它可以通过浏览器的点击执行终端命令。 - STEEL


快捷方式:

var express = require('express');
var app = express();
app.use('/', express.static(__dirname + '/../public')); // ← adjust
app.listen(3000, function() { console.log('listening'); });

你的方式:

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

http.createServer(function (req, res) {
    console.dir(req.url);

    // will get you  '/' or 'index.html' or 'css/styles.css' ...
    // • you need to isolate extension
    // • have a small mimetype lookup array/object
    // • only there and then reading the file
    // •  delivering it after setting the right content type

    res.writeHead(200, {'Content-Type': 'text/html'});

    res.end('ok');
}).listen(3001);

27
2018-02-07 08:28





我认为从字典中查找内容类型更简洁,而不是处理switch语句:

var contentTypesByExtension = {
    'html': "text/html",
    'js':   "text/javascript"
};

...

    var contentType = contentTypesByExtension[fileExtension] || 'text/plain';

19
2017-11-24 21:08



是的,看起来比Eric B. Sowell使用的“切换”解决方案更优雅(参见选定的答案)。谢谢。 - idophir
这个答案完全脱离了上下文......它引用了这条评论中的这个链接 - stackoverflow.com/questions/6084360/... (是的,无论如何,互联网被打破) - Michael Freeman


这基本上是连接版本3的已接受答案的更新版本:

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

var app = connect();

app.use(serveStatic(__dirname, {'index': ['index.html']}));
app.listen(3000);

我还添加了一个默认选项,以便将index.html作为默认选项。


14
2018-06-20 17:40





你不需要使用任何NPM模块来运行一个简单的服务器,有一个非常小的库叫做“NPM免费服务器“对于节点:

50行代码,如果您请求文件或文件夹,则输出,如果工作失败,则为红色或绿色。小于1KB(缩小)。


11
2017-11-09 16:10



很棒的选择。提供html,css,js和图像。非常适合调试。只需将此代码替换为server.js即可。 - pollaris
我希望我能添加更多的赞成!这很棒!我做了很小的改变 var filename = path.join(process.cwd() + '/dist/', uri);  从服务器到 DIST 夹。我把代码放进去了 server.js 而且它 只是工作 当我打字 npm start - John Henckel


如果您在PC上安装了节点,可能您有NPM,如果您不需要NodeJS,可以使用 服务 包装:

1 - 在PC上安装软件包:

npm install -g serve

2 - 提供静态文件夹:

serve <path> 
d:> serve d:\StaticSite

它将显示您的静态文件夹所在的端口,只需导航到主机,如:

http://localhost:3000

9
2018-02-23 17:57