NodeJS 中的基本静态文件服务器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7268033/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 14:31:09  来源:igfitidea点击:

Basic static file server in NodeJS

httpnode.jswebserver

提问by slapthelownote

I'm trying to create a static file server in nodejs more as an exercise to understand node than as a perfect server. I'm well aware of projects like Connect and node-static and fully intend to use those libraries for more production-ready code, but I also like to understand the basics of what I'm working with. With that in mind, I've coded up a small server.js:

我试图在 nodejs 中创建一个静态文件服务器,更多的是作为理解 node 的练习,而不是作为一个完美的服务器。我非常了解 Connect 和 node-static 等项目,并且完全打算将这些库用于更多生产就绪代码,但我也喜欢了解我正在使用的基础知识。考虑到这一点,我编写了一个小的 server.js:

var http = require('http'),
    url = require('url'),
    path = require('path'),
    fs = require('fs');
var mimeTypes = {
    "html": "text/html",
    "jpeg": "image/jpeg",
    "jpg": "image/jpeg",
    "png": "image/png",
    "js": "text/javascript",
    "css": "text/css"};

http.createServer(function(req, res) {
    var uri = url.parse(req.url).pathname;
    var filename = path.join(process.cwd(), uri);
    path.exists(filename, function(exists) {
        if(!exists) {
            console.log("not exists: " + filename);
            res.writeHead(200, {'Content-Type': 'text/plain'});
            res.write('404 Not Found\n');
            res.end();
        }
        var mimeType = mimeTypes[path.extname(filename).split(".")[1]];
        res.writeHead(200, mimeType);

        var fileStream = fs.createReadStream(filename);
        fileStream.pipe(res);

    }); //end path.exists
}).listen(1337);

My question is twofold

我的问题是双重的

  1. Is this the "right" way to go about creating and streaming basic html etc in node or is there a better/more elegant/more robust method ?

  2. Is the .pipe() in node basically just doing the following?

  1. 这是在节点中创建和流式传输基本 html 等的“正确”方式,还是有更好/更优雅/更健壮的方法?

  2. 节点中的 .pipe() 基本上只是在执行以下操作吗?

.

.

var fileStream = fs.createReadStream(filename);
fileStream.on('data', function (data) {
    res.write(data);
});
fileStream.on('end', function() {
    res.end();
});

Thanks everyone!

谢谢大家!

采纳答案by stewe

  • Your basic server looks good, except:

    There is a returnstatement missing.

    res.write('404 Not Found\n');
    res.end();
    return; // <- Don't forget to return here !!
    

    And:

    res.writeHead(200, mimeType);

    should be:

    res.writeHead(200, {'Content-Type':mimeType});

  • Yes pipe()does basically that, it also pauses/resumes the source stream (in case the receiver is slower). Here is the source code of the pipe()function: https://github.com/joyent/node/blob/master/lib/stream.js

  • 您的基本服务器看起来不错,除了:

    return缺少一个声明。

    res.write('404 Not Found\n');
    res.end();
    return; // <- Don't forget to return here !!
    

    和:

    res.writeHead(200, mimeType);

    应该:

    res.writeHead(200, {'Content-Type':mimeType});

  • Yespipe()基本上就是这样,它还会暂停/恢复源流(以防接收器速度较慢)。这里是pipe()函数的源代码:https: //github.com/joyent/node/blob/master/lib/stream.js

回答by Jason Sebring

Less is more

少即是多

Just go command prompt first on your project and use

只需在您的项目中先进入命令提示符并使用

$ npm install express

Then write your app.js code like so:

然后像这样编写你的 app.js 代码:

var express = require('express'),
app = express(),
port = process.env.PORT || 4000;

app.use(express.static(__dirname + '/public'));
app.listen(port);

You would then create a "public" folder where you place your files. I tried it the harder way first but you have to worry about mime types which is just having to map stuff which is time consuming and then worry about response types, etc. etc. etc.... no thank you.

然后,您将创建一个“公共”文件夹,用于放置您的文件。我首先尝试了更难的方法,但您必须担心 mime 类型,它只需要映射耗时的内容,然后担心响应类型等等等……不,谢谢。

回答by Jeff Ward

I like understanding what's going on under the hood as well.

我也喜欢了解幕后发生的事情。

I noticed a few things in your code that you probably want to clean up:

我注意到您的代码中有一些您可能想要清理的内容:

  • It crashes when filename points to a directory, because exists is true and it tries to read a file stream. I used fs.lstatSync to determine directory existence.

  • It isn't using the HTTP response codes correctly (200, 404, etc)

  • While MimeType is being determined (from the file extension), it isn't being set correctly in res.writeHead (as stewe pointed out)

  • To handle special characters, you probably want to unescape the uri

  • It blindly follows symlinks (could be a security concern)

  • 当 filename 指向一个目录时它会崩溃,因为exists为真并且它尝试读取文件流。我使用 fs.lstatSync 来确定目录是否存在。

  • 它没有正确使用 HTTP 响应代码(200、404 等)

  • 虽然 MimeType 正在被确定(从文件扩展名),但它没有在 res.writeHead 中正确设置(正如斯图指出的那样)

  • 要处理特殊字符,您可能需要对 uri 进行转义

  • 它盲目地遵循符号链接(可能是一个安全问题)

Given this, some of the apache options (FollowSymLinks, ShowIndexes, etc) start to make more sense. I've update the code for your simple file server as follows:

鉴于此,一些 apache 选项(FollowSymLinks、ShowIndexes 等)开始变得更有意义。我已经更新了您的简单文件服务器的代码,如下所示:

var http = require('http'),
    url = require('url'),
    path = require('path'),
    fs = require('fs');
var mimeTypes = {
    "html": "text/html",
    "jpeg": "image/jpeg",
    "jpg": "image/jpeg",
    "png": "image/png",
    "js": "text/javascript",
    "css": "text/css"};

http.createServer(function(req, res) {
  var uri = url.parse(req.url).pathname;
  var filename = path.join(process.cwd(), unescape(uri));
  var stats;

  try {
    stats = fs.lstatSync(filename); // throws if path doesn't exist
  } catch (e) {
    res.writeHead(404, {'Content-Type': 'text/plain'});
    res.write('404 Not Found\n');
    res.end();
    return;
  }


  if (stats.isFile()) {
    // path exists, is a file
    var mimeType = mimeTypes[path.extname(filename).split(".").reverse()[0]];
    res.writeHead(200, {'Content-Type': mimeType} );

    var fileStream = fs.createReadStream(filename);
    fileStream.pipe(res);
  } else if (stats.isDirectory()) {
    // path exists, is a directory
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.write('Index of '+uri+'\n');
    res.write('TODO, show index?\n');
    res.end();
  } else {
    // Symbolic link, other?
    // TODO: follow symlinks?  security?
    res.writeHead(500, {'Content-Type': 'text/plain'});
    res.write('500 Internal server error\n');
    res.end();
  }

}).listen(1337);

回答by Chí Nguy?n

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

var server = http.createServer(function (req, res) {
  res.writeHead(200, { 'content-type': 'text/plain' })

  fs.createReadStream(process.argv[3]).pipe(res)
})

server.listen(Number(process.argv[2]))

回答by Aerik

How about this pattern, which avoids checking separately that the file exists

这种模式如何,避免单独检查文件是否存在

        var fileStream = fs.createReadStream(filename);
        fileStream.on('error', function (error) {
            response.writeHead(404, { "Content-Type": "text/plain"});
            response.end("file not found");
        });
        fileStream.on('open', function() {
            var mimeType = mimeTypes[path.extname(filename).split(".")[1]];
            response.writeHead(200, {'Content-Type': mimeType});
        });
        fileStream.on('end', function() {
            console.log('sent file ' + filename);
        });
        fileStream.pipe(response);

回答by Aerik

I made a httpServer function with extra features for general usage based on @Jeff Ward answer

我根据@Jeff Ward 的回答制作了一个带有额外功能的 httpServer 函数,用于一般用途

  1. custtom dir
  2. index.html returns if req === dir
  1. 自定义目录
  2. index.html 如果 req === dir 返回

Usage:

用法:

httpServer(dir).listen(port);

https://github.com/kenokabe/ConciseStaticHttpServer

https://github.com/kenokabe/ConciseStaticHttpServer

Thanks.

谢谢。

回答by kaore

the st modulemakes serving static files easy. Here is an extract of README.md:

ST模块,使容易提供静态文件。这是 README.md 的摘录:

var mount = st({ path: __dirname + '/static', url: '/static' })
http.createServer(function(req, res) {
  var stHandled = mount(req, res);
  if (stHandled)
    return
  else
    res.end('this is not a static file')
}).listen(1338)

回答by ffleandro

@JasonSebring answer pointed me in the right direction, however his code is outdated. Here is how you do it with the newest connectversion.

@JasonSebring 的回答为我指明了正确的方向,但他的代码已经过时。以下是使用最新connect版本的方法。

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

var app = connect()
    .use(serveStatic('public'))
    .use(serveIndex('public', {'icons': true, 'view': 'details'}))
    .listen(3000);

In connectGitHub Repositorythere are other middlewares you can use.

connectGitHub Repository 中,您可以使用其他中间件。