本文主要讲解serve-index的用法和实现原理(源代码分析)。
一 说明
serve-index的功能是将文件夹中文件列表显示到浏览器中。
serve-index是一个NodeJS模块,可以通过NPM安装。
二 安装方法
$ npm install serve-index --save
三 使用方法
通过ExpressJS创建静态服务器时,使用serve-index方法如下:
1 var express = require('express'); 2 var serveIndex = require('serve-index'); 3 var app = express(); 4 5 app.use(express.static('staticServer')); 6 7 app.use(serveIndex('staticServer',{ 'icons': true })); 8 9 var server = app.listen(3000, function () { 10 var host = server.address().address; 11 var port = server.address().port; 12 13 console.log('Example app listening at http://%s:%s', host, port); 14 });
通过nodeJS的serve-static创建静态服务器时,用法如下:
1 var finalhandler = require('finalhandler') 2 var http = require('http') 3 var serveIndex = require('serve-index') 4 var serveStatic = require('serve-static') 5 6 // Serve directory indexes for public/ftp folder (with icons) 7 var index = serveIndex('public/ftp', {'icons': true}) 8 9 // Serve up public/ftp folder files 10 var serve = serveStatic('public/ftp') 11 12 // Create server 13 var server = http.createServer(function onRequest(req, res){ 14 var done = finalhandler(req, res) 15 serve(req, res, function onNext(err) { 16 if (err) return done(err) 17 index(req, res, done) 18 }) 19 }) 20 21 // Listen 22 server.listen(3000)
四 接口说明
serveIndex(path,options)
1.功能说明:
创建一个中间件函数。
2.返回值:
中间件函数,这个中间件创建了文件夹中所有文件的索引目录。
3.参数:
path:
静态文件服务器的路径地址,一般与创建静态服务器地址一致。
options:
ServeIndex在options对象中接受这些属性:
filter
类型:Function;默认值为false
。
功能:文件夹中每个文件都调用filter函数进行过滤,实际就是让开发人员可以决定哪些文件显示哪些不显示,也可以改变文件名。如果该函数返回false(或者空字符串)【注意:只测试了这两种】,则不显示该文件夹。
参数:filter(filename, index, files, dir)
filename
是文件名,index
是数组索引,files
是文件数组,是文件dir
所在的绝对路径。
下边是filter的一个示例,用于过滤不显示READEME.md文件。
1 var options = { 2 icons : true, 3 filter : serveIndexFilter 4 }; 5 6 function serveIndexFilter(filename, index, list, path) { 7 console.log(filename); 8 console.log(index); 9 console.log(list); 10 console.log(path); 11 12 // 过滤README.md文件,如果是该文件,就不显示 13 if (filename.match('README.md')) { 14 return ''; 15 } else { 16 return filename; 17 } 18 } 19 20 app.use(serveIndex('staticServer', options));
hidden
类型:Boolean
默认值:false
功能:是否隐藏文件名是“.”的文件。设置为true时,显示;设置为false时,不显示。
icons
显示文件图标。默认为false
。
stylesheet
CSS样式表的可选路径。默认为内置样式表。
template
HTML模板的可选路径或将呈现HTML字符串的函数。默认为内置模板。
给定字符串时,该字符串将用作要加载的文件路径,然后在模板中替换以下标记:
{directory}
使用目录的名称。
{files}
使用无序的文件链接列表的HTML。
{linked-path}
使用目录链接的HTML。
{style}
使用指定的样式表和嵌入的图像。
当作为函数给出时,该函数被调用为template(locals, callback)
,并且需要调用它callback(error, htmlString)
。以下是提供的当地人:
directory
是显示的目录(/
根在哪里)。
displayIcons
是否应该呈现图标的布尔值。
fileList
是目录中的已排序文件数组。该数组包含具有以下属性的对象:
name
是文件的相对名称。
stat
是fs.Stats
文件的对象。
path
是完整的文件系统路径directory
。
style
是默认样式表或stylesheet
选项的内容。
viewName
是view
选项提供的视图名称。
view
类型:String
功能:显示模式。可选值:”tiles”、"details"
。默认为tiles
。
说明:设置为details时,显示样子如下:
五 实现原理
通过上边用法可以知道,serveIndex方法返回一个中间件函数,这个中间件函数会在服务器接收到请求时执行,这个函数的主要功能是根据请求url地址,读取本地文件夹中对应的文件,创建一个HTML文件,生成文件列表DOM、样式等插入HTML文件中,并将这个HTML作为请求内容返回给浏览器显示,这样就实现了将文件夹内容显示到浏览器中了。
详细步骤如下:
5.1.serveIndex方法创建并返回中间件函数,该中间件函数作为app.use()的参数,这样就相当于给服务器注册了一个回调函数,当有请求过来时,就会调用该函数。
app.use(serveIndex('staticServer', options));
serveIndex的缩略代码(省去了返回的函数代码)如下:
1 function serveIndex(root, options) { 2 var opts = options || {}; 3 4 // root required 5 if (!root) { 6 throw new TypeError('serveIndex() root path required'); 7 } 8 9 // resolve root to absolute and normalize 10 var rootPath = normalize(resolve(root) + sep); 11 12 var filter = opts.filter; 13 var hidden = opts.hidden; 14 var icons = opts.icons; 15 var stylesheet = opts.stylesheet || defaultStylesheet; 16 var template = opts.template || defaultTemplate; 17 var view = opts.view || 'tiles'; 18 19 return function (req, res, next) { 20 //... 21 }; 22 };
5.2 当服务器受到浏览器请求时,会执行上边返回的中间的函数,该函数主要功能是根据请求url地址,读取本地文件夹中对应的文件,创建一个HTML文件,生成文件列表DOM、样式等插入HTML文件中,并将这个HTML作为请求内容返回给浏览器显示,这样就实现了将文件夹内容显示到浏览器中了。
重点代码片段如下:
通过NodeJS的fs文件接口读取请求路径中的文件:
1 fs.readdir(path, function(err, files){ 2 if (err) return next(err); 3 if (!hidden) files = removeHidden(files); 4 if (filter) files = files.filter(function(filename, index, list) { 5 return filter(filename, index, list, path); 6 }); 7 files.sort(); 8 9 // content-negotiation 10 var accept = accepts(req); 11 var type = accept.type(mediaTypes); 12 13 // not acceptable 14 if (!type) return next(createError(406)); 15 serveIndex[mediaType[type]](req, res, files, next, originalDir, showUp, icons, path, view, template, stylesheet); 16 });
上边代码中最后调用的serveIndex[mediaType[type]],实际是调用serveIndex.html()方法,该方法主要做了2件事:创建HTML文件和文件列表DOM,并设置给请求头的body中。
1 fs.readFile(stylesheet, 'utf8', function (err, style) { 2 if (err) return next(err); 3 4 // create locals for rendering 5 var locals = { 6 directory: dir, 7 displayIcons: Boolean(icons), 8 fileList: fileList, 9 path: path, 10 style: style, 11 viewName: view 12 }; 13 14 // render html 15 render(locals, function (err, body) { 16 if (err) return next(err); 17 send(res, 'text/html', body) 18 }); 19 });
1 function createHtmlRender(template) { 2 return function render(locals, callback) { 3 // read template 4 fs.readFile(template, 'utf8', function (err, str) { 5 if (err) return callback(err); 6 7 var body = str 8 .replace(/{style}/g, locals.style.concat(iconStyle(locals.fileList, locals.displayIcons))) 9 .replace(/{files}/g, createHtmlFileList(locals.fileList, locals.directory, locals.displayIcons, locals.viewName)) 10 .replace(/{directory}/g, escapeHtml(locals.directory)) 11 .replace(/{linked-path}/g, htmlPath(locals.directory)); 12 13 callback(null, body); 14 }); 15 }; 16 }
1 function send (res, type, body) { 2 // security header for content sniffing 3 res.setHeader('X-Content-Type-Options', 'nosniff') 4 5 // standard headers 6 res.setHeader('Content-Type', type + '; charset=utf-8') 7 res.setHeader('Content-Length', Buffer.byteLength(body, 'utf8')) 8 9 // body 10 res.end(body, 'utf8') 11 }
参考资料&内容来源:
Express官网:http://www.expressjs.com.cn/en/resources/middleware/serve-index.html
最新评论