资讯专栏INFORMATION COLUMN

用Node提供静态文件服务

gecko23 / 2404人阅读

摘要:前言对于一个应用,提供静态文件图片服务常常是必须的。本文将介绍如何做一个自己的静态文件服务器。虽然已经品尝到了成功的滋味,但这个静态文件服务器还不够完整,因为它很容易出错。

前言

对于一个web应用,提供静态文件(CSS、JavaScript、图片)服务常常是必须的。本文将介绍如何做一个自己的静态文件服务器。

创建一个静态文件服务器

每个静态文件服务器都有个根目录,也就是提供文件服务的基础目录。所以我们要在即将创建的服务器上定义一个root变量,它将作为我们这个静态文件服务器的根目录:

var http = require("http")
var join = require("path").join
var fs = require("fs")

var root = __dirname

__dirname 在Node中是一个神奇的变量,它的值是该文件所在目录的路径。在本例中,服务器会将这个脚本所在的目录作为静态文件的根目录。

有了文件的路径,还需要传输文件的内容。
这可以用fs.ReadStream完成,它是Node中Stream类之一。成功调用 fs.createReadStream() 会返回一个新的 fs.ReadStream 对象。
下面的代码实现了一个简单但功能完备的文件服务器。

var server = http.createServer(function(req, res){
  let path = join(root, req.url)
  let stream = fs.createReadStream(path)
  stream.on("data", function(chunk){
    res.write(chunk)
  })
  stream.on("end", function(){
    res.end()
  })
})

server.listen(3000)

这个文件服务器大体能用,但还有很多细节需要考虑。接下来我们要优化数据的传输,同时也精简一下服务器的代码。

用STREAM.PIPE()优化数据传输

虽然上面的代码看上去还不错,但Node还提供了更高级的实现机制:Stream.pipe()。用这个方法可以极大简化服务器的代码。 优化后代码如下:

var server = http.createServer(function(req, res){
  let path = join(root, req.url)
  let stream = fs.createReadStream(path)
  stream.pipe(res)
})

server.listen(3000)

这种写法,是不是更简单,更清晰了呢?

理解流和管道

流是Node中很重要的一个概念,你可以把Node中的管道想象成水管,如果你想让某个源头(比如热水器)流出来的水流到一个目的地(比如厨房的水龙头),可以在中间加一个管道把它们连起来,这样水就会顺着管道从源头流到目的地。
Node中的管道也是这样,但其中流动的不是水,而是来自源头(即ReadableStream)的数据,管道可以让它们“流动”到某个目的地(即WritableStream)。你可以用pipe方法把管道连起来:

ReadableStream.pipe(WritableStream)

读取一个文件(ReadableStream)并把其中的内容写到另一个文件中(WritableStream)用的就是管道:

let readStream = fs.createReadStream("./original.txt") 
let writeStream = fs.createWriteStream("./copy.txt") 
readStream.pipe(writeStream)

所有ReadableStream都能接入任何一个WritableStream。比如HTTP请求(req)对
象就是ReadableStream,你可以让其中的内容流动到文件中:

req.pipe(fs.createWriteStream("./req-body.txt")) 
运行

现在我们来运行上面的代码,我们在根目录下放一张图片,比如peiqi.jpg。
在浏览器中输入http://127.0.0.1:3000/peiqi.jpg,发现可爱的peiqi已经出现在你的面前了。peiqi.jpg被当作响应主体从http服务器送到了客户端(浏览器)。

虽然已经品尝到了成功的滋味,但这个静态文件服务器还不够完整,因为它很容易出错。想象一下,如果用户不小心输入了一个并不存在的资源,比如abc.html,服务器就会马上崩掉。所以我们还得给这个文件服务器加上错误处理机制,让它足够健壮

处理服务器错误

在Node中,所有继承了EventEmitter的类都可能会发出error事件。为了监听错误,在fs.ReadStream上注册一个error事件处理器(比如下面这段代码),返回响应状态码500表明有服务器内部错误:

  stream.on("error", function(err){
    res.statusCode = 500
    res.end("服务器内部错误")
  })
用fs.stat()实现错误处理

我们可以用fs.stat()来获取文件的相关信息,如果文件不存在,fs.stat()会在err.code中放入ENOENT作为响应,然后你可以返回错误码404,向客户端表明文件未找到。如果fs.stat()返回了其他错误码,你可以返回通用的错误码500。
重构后的代码如下:

var server = http.createServer(function(req, res){
  let path = join(root, req.url)

  fs.stat(path, function(err, stat) {
    if (err) {
      if ("ENOENT" == err.code) {
        res.statusCode = 404
        res.end("Not Found")
      } else {
        res.statusCode = 500
        res.end("服务器内部错误")
      }
    } else { // 有该文件
      res.setHeader("Content-Length", stat.size)
      var stream = fs.createReadStream(path)
      stream.pipe(res)

      stream.on("error", function(err) { // 如果读取文件出错
        res.statusCode = 500
        res.end("服务器内部错误")
      })
    }
  })
})

server.listen(3000)
注意

本节构建的文件服务器是个简化版。如果你想把它放到生产环境中,应该更全面地检查输入的有效性,以防用户通过目录遍历攻击访问到你本来不想开放给他们的那部分内容。

小结

读到这里,相信聪明的你已经掌握了如何用Node创建一个静态服务器,下一篇文章我会给大家介绍如何用Node处理用户上传的文件并存放到服务器中。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/95954.html

相关文章

  • 5个提高Node.js应性能的技巧

    摘要:如果你有一个高流量的站点,提高性能的第一步是在你的前面放一个反向代理服务器。使用在一个已经存在的服务器前做反向代理,作为的一个核心应用,已经被用于全世界成千上万的站点中。 如果你的 node 服务器前面没有 nginx, 那么你可能做错了。— Bryan Hughes Node.js 是使用 最流行的语言— JavaScript 构建服务器端应用的领先工具 。由于可以同时提供 web ...

    k00baa 评论0 收藏0
  • 记最近一次Nodejs全栈开发经历

    摘要:背景前段时间大部门下新成立了一个推广百度文字识别图像识别等科技能力在金融领域应用的子部门。而且在百度内部提倡的也是使用和。百度内部有现成的服务接入文档。 背景: 前段时间大部门下新成立了一个推广百度OCR、文字识别、图像识别等科技能力在金融领域应用的子部门。因为部门刚成立,基础设施和人力都是欠缺的。当时分到我们部门的任务是抽调一个人做新部门主站前端开发工作。本来说的是只负责页面的开发工...

    Lycheeee 评论0 收藏0
  • 入门node.js你必须知道的那些事

    摘要:入门你必须知道的那些事最基本的一些操作和概念用执行一段代码在命令行中用切换到桌面创建一个文件夹和并用命令切换到这个文件夹创建一个文件并写上简单的代码在命令行中输入命令行会输出引用文件的方式采用了规范通过来引入一个文件新建文件并在文件中引入执 入门node.js你必须知道的那些事 最基本的一些操作和概念 用node执行一段js代码 在命令行中用cd切换到桌面 创建一个文件夹和并用cd命...

    learn_shifeng 评论0 收藏0
  • [手把手系列之]Docker 部署 vue 项目

    摘要:部署项目写在前面作为轻量级虚拟化技术,拥有持续集成版本控制可移植性隔离性和安全性等优势。容器可以被创建启动停止删除暂停等。重新运行应用容器直接基于镜像来启动容器,运行命令将宿主机的挂载到容器的目录上。Docker 部署 vue 项目 1.写在前面: Docker 作为轻量级虚拟化技术,拥有持续集成、版本控制、可移植性、隔离性和安全性等优势。本文使用Docker来部署一个vue的前端应用,并尽...

    VPointer 评论0 收藏0

发表评论

0条评论

gecko23

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<