前言对于Web应用程序,通常需要提供静态文件(CSS、JavaScript、图像)。本文将介绍如何制作自己的静态文件服务器。创建静态文件服务器每个静态文件服务器都有一个根目录,这是提供文件服务的基本目录。所以我们需要在我们即将创建的服务器上定义一个根变量,作为我们静态文件服务器的根目录:varhttp=require('http')varjoin=require('path').joinvarfs=require('fs')varroot=__dirname__dirname是Node中的一个神奇变量,其值是文件所在目录的路径。在这个例子中,服务器将使用这个脚本所在的目录作为静态文件的根目录。有了文件的路径,就需要传输文件的内容。这可以通过fs.ReadStream来完成,它是Node中的Stream类之一。成功调用fs.createReadStream()会返回一个新的fs.ReadStream对象。下面的代码实现了一个简单但功能齐全的文件服务器。varserver=http.createServer(function(req,res){letpath=join(root,req.url)letstream=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()。使用这种方法可以大大简化服务器的代码。优化后的代码如下:varserver=http.createServer(function(req,res){letpath=join(root,req.url)letstream=fs.createReadStream(path)stream.pipe(res)})server.listen(3000)这样写是不是更简单明了?理解流和管道流是Node中一个非常重要的概念。您可以将Node中的管道想象成水管。如果想让水从源头(比如热水器)流到目的地(比如厨房水龙头),可以在中间加一根管子把它们连接起来,这样水就会沿着管子从源头流出。源到目的地。Node中的管道也是如此,只不过流在里面的不是水,而是来自源头的数据(即ReadableStream),管道让它们“流”到某个目的地(即WritableStream)。可以使用pipe方法连接管道:ReadableStream.pipe(WritableStream)读取一个文件(ReadableStream)并使用管道将其内容写入另一个文件(WritableStream):letreadStream=fs.createReadStream('./original.txt')letwriteStream=fs.createWriteStream('./copy.txt')readStream.pipe(writeStream)所有ReadableStreams都可以访问任何WritableStream。例如,HTTP请求(req)对象是一个ReadableStream,你可以让内容流入文件:req.pipe(fs.createWriteStream('./req-body.txt'))运行现在让我们运行上面的代码,我们在根目录放一张图片,比如peiqi.jpg。在浏览器中输入http://127.0.0.1:3000/peiqi.jpg,发现可爱的佩奇已经出现在你的面前了。peiqi.jpg作为响应体从http服务器发送到客户端(浏览器)。虽然已经尝到了成功的滋味,但这个静态文件服务器并不完整,因为它容易出错。想象一下,如果用户不小心输入了一个不存在的资源,比如abc.html,服务器会立刻崩溃。所以我们必须给这个文件服务器添加一个错误处理机制,让它足够健壮。处理服务器错误在Node中,所有继承EventEmitter的类都可能发出错误事件。为了监控错误,在fs.ReadStream上注册一个错误事件处理器(比如下面的代码),返回一个500的响应状态码表示有内部服务器错误:stream.on('error',function(err){res.statusCode=500res.end('Internalservererror')})使用fs.stat()实现错误处理如果文件不存在,我们可以使用fs.stat()获取有关文件的信息,fs.stat()会在err.code中放入ENOENT作为响应,然后可以返回错误代码404来向客户端表明文件没有找到。如果fs.stat()返回其他错误代码,您可以返回通用错误代码500。重构后的代码如下:varserver=http.createServer(function(req,res){letpath=join(root,req.url)fs.stat(path,function(err,stat){if(err){if('ENOENT'==err.code){res.statusCode=404res.end('未找到')}else{res.statusCode=500res.end('内部服务器错误')}}else{//有文件res.setHeader('Content-Length',stat.size)varstream=fs.createReadStream(path)stream.pipe(res)stream.on('error',function(err){//如果读取文件errorres.statusCode=500res.end('Internalservererror')})}})})server.listen(3000)注意本节搭建的文件服务器是简化版。如果你想投入生产,你应该更全面地检查输入的有效性,以防用户通过目录遍历攻击访问你不想向他们开放的部分内容。小结看完本文,相信你已经掌握了如何使用Node创建静态服务器的方法。在下一篇文章中,我将介绍如何使用Node来处理用户上传的文件并存储到服务器中。
