本文主要讲解serve-index的用法和实现原理(源代码分析)。

一 说明

serve-index的功能是将文件夹中文件列表显示到浏览器中。

serve-index是一个NodeJS模块,可以通过NPM安装。

二 安装方法

$ npm install serve-index --save

三 使用方法

通过ExpressJS创建静态服务器时,使用serve-index方法如下:

 var express = require('express');
var serveIndex = require('serve-index');
var app = express(); app.use(express.static('staticServer')); app.use(serveIndex('staticServer',{ 'icons': true })); var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port; console.log('Example app listening at http://%s:%s', host, port);
});

通过nodeJS的serve-static创建静态服务器时,用法如下:

 var finalhandler = require('finalhandler')
var http = require('http')
var serveIndex = require('serve-index')
var serveStatic = require('serve-static') // Serve directory indexes for public/ftp folder (with icons)
var index = serveIndex('public/ftp', {'icons': true}) // Serve up public/ftp folder files
var serve = serveStatic('public/ftp') // Create server
var server = http.createServer(function onRequest(req, res){
var done = finalhandler(req, res)
serve(req, res, function onNext(err) {
if (err) return done(err)
index(req, res, done)
})
}) // Listen
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文件。

 var options = {
icons : true,
filter : serveIndexFilter
}; function serveIndexFilter(filename, index, list, path) {
console.log(filename);
console.log(index);
console.log(list);
console.log(path); // 过滤README.md文件,如果是该文件,就不显示
if (filename.match('README.md')) {
return '';
} else {
return filename;
}
} 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 是文件的相对名称。
    • statfs.Stats文件的对象。
  • path是完整的文件系统路径directory
  • style是默认样式表或stylesheet选项的内容。
  • viewNameview选项提供的视图名称。
view

类型:String

功能:显示模式。可选值:"tiles"、"details"。默认为tiles

说明:设置为details时,显示样子如下:

五 实现原理

通过上边用法可以知道,serveIndex方法返回一个中间件函数,这个中间件函数会在服务器接收到请求时执行,这个函数的主要功能是根据请求url地址,读取本地文件夹中对应的文件,创建一个HTML文件,生成文件列表DOM、样式等插入HTML文件中,并将这个HTML作为请求内容返回给浏览器显示,这样就实现了将文件夹内容显示到浏览器中了。

详细步骤如下:

5.1.serveIndex方法创建并返回中间件函数,该中间件函数作为app.use()的参数,这样就相当于给服务器注册了一个回调函数,当有请求过来时,就会调用该函数。

app.use(serveIndex('staticServer', options));

serveIndex的缩略代码(省去了返回的函数代码)如下:

 function serveIndex(root, options) {
var opts = options || {}; // root required
if (!root) {
throw new TypeError('serveIndex() root path required');
} // resolve root to absolute and normalize
var rootPath = normalize(resolve(root) + sep); var filter = opts.filter;
var hidden = opts.hidden;
var icons = opts.icons;
var stylesheet = opts.stylesheet || defaultStylesheet;
var template = opts.template || defaultTemplate;
var view = opts.view || 'tiles'; return function (req, res, next) {
//...
};
};

5.2 当服务器受到浏览器请求时,会执行上边返回的中间的函数,该函数主要功能是根据请求url地址,读取本地文件夹中对应的文件,创建一个HTML文件,生成文件列表DOM、样式等插入HTML文件中,并将这个HTML作为请求内容返回给浏览器显示,这样就实现了将文件夹内容显示到浏览器中了。

重点代码片段如下:

通过NodeJS的fs文件接口读取请求路径中的文件:

       fs.readdir(path, function(err, files){
if (err) return next(err);
if (!hidden) files = removeHidden(files);
if (filter) files = files.filter(function(filename, index, list) {
return filter(filename, index, list, path);
});
files.sort(); // content-negotiation
var accept = accepts(req);
var type = accept.type(mediaTypes); // not acceptable
if (!type) return next(createError(406));
serveIndex[mediaType[type]](req, res, files, next, originalDir, showUp, icons, path, view, template, stylesheet);
});

上边代码中最后调用的serveIndex[mediaType[type]],实际是调用serveIndex.html()方法,该方法主要做了2件事:创建HTML文件和文件列表DOM,并设置给请求头的body中。

     fs.readFile(stylesheet, 'utf8', function (err, style) {
if (err) return next(err); // create locals for rendering
var locals = {
directory: dir,
displayIcons: Boolean(icons),
fileList: fileList,
path: path,
style: style,
viewName: view
}; // render html
render(locals, function (err, body) {
if (err) return next(err);
send(res, 'text/html', body)
});
});
 function createHtmlRender(template) {
return function render(locals, callback) {
// read template
fs.readFile(template, 'utf8', function (err, str) {
if (err) return callback(err); var body = str
.replace(/\{style\}/g, locals.style.concat(iconStyle(locals.fileList, locals.displayIcons)))
.replace(/\{files\}/g, createHtmlFileList(locals.fileList, locals.directory, locals.displayIcons, locals.viewName))
.replace(/\{directory\}/g, escapeHtml(locals.directory))
.replace(/\{linked-path\}/g, htmlPath(locals.directory)); callback(null, body);
});
};
}
 function send (res, type, body) {
// security header for content sniffing
res.setHeader('X-Content-Type-Options', 'nosniff') // standard headers
res.setHeader('Content-Type', type + '; charset=utf-8')
res.setHeader('Content-Length', Buffer.byteLength(body, 'utf8')) // body
res.end(body, 'utf8')
}

参考资料&内容来源:

Express官网:http://www.expressjs.com.cn/en/resources/middleware/serve-index.html

serve-index用法、实现原理(源码解读)的更多相关文章

  1. Vue 源码解读(4)—— 异步更新

    前言 上一篇的 Vue 源码解读(3)-- 响应式原理 说到通过 Object.defineProperty 为对象的每个 key 设置 getter.setter,从而拦截对数据的访问和设置. 当对 ...

  2. http-proxy-middleware使用方法和实现原理(源码解读)

    本文主要讲http-proxy-middleware用法和实现原理. 一 简介 http-proxy-middleware用于后台将请求转发给其它服务器. 例如:我们当前主机A为http://loca ...

  3. Webpack探索【16】--- 懒加载构建原理详解(模块如何被组建&如何加载)&源码解读

    本文主要说明Webpack懒加载构建和加载的原理,对构建后的源码进行分析. 一 说明 本文以一个简单的示例,通过对构建好的bundle.js源码进行分析,说明Webpack懒加载构建原理. 本文使用的 ...

  4. Webpack探索【15】--- 基础构建原理详解(模块如何被组建&如何加载)&源码解读

    本文主要说明Webpack模块构建和加载的原理,对构建后的源码进行分析. 一 说明 本文以一个简单的示例,通过对构建好的bundle.js源码进行分析,说明Webpack的基础构建原理. 本文使用的W ...

  5. 2,MapReduce原理及源码解读

    MapReduce原理及源码解读 目录 MapReduce原理及源码解读 一.分片 灵魂拷问:为什么要分片? 1.1 对谁分片 1.2 长度是否为0 1.3 是否可以分片 1.4 分片的大小 1.5 ...

  6. Vue 源码解读(3)—— 响应式原理

    前言 上一篇文章 Vue 源码解读(2)-- Vue 初始化过程 详细讲解了 Vue 的初始化过程,明白了 new Vue(options) 都做了什么,其中关于 数据响应式 的实现用一句话简单的带过 ...

  7. 第二十三课:jQuery.event.add的原理以及源码解读

    本课主要来讲解一下jQuery是如何实现它的事件系统的. 我们先来看一个问题: 如果有一个表格有100个tr元素,每个都要绑定mouseover/mouseout事件,改成事件代理的方式,可以节省99 ...

  8. Alamofire源码解读系列(四)之参数编码(ParameterEncoding)

    本篇讲解参数编码的内容 前言 我们在开发中发的每一个请求都是通过URLRequest来进行封装的,可以通过一个URL生成URLRequest.那么如果我有一个参数字典,这个参数字典又是如何从客户端传递 ...

  9. Alamofire源码解读系列(八)之安全策略(ServerTrustPolicy)

    本篇主要讲解Alamofire中安全验证代码 前言 作为开发人员,理解HTTPS的原理和应用算是一项基本技能.HTTPS目前来说是非常安全的,但仍然有大量的公司还在使用HTTP.其实HTTPS也并不是 ...

  10. SDWebImage源码解读 之 UIImage+GIF

    第二篇 前言 本篇是和GIF相关的一个UIImage的分类.主要提供了三个方法: + (UIImage *)sd_animatedGIFNamed:(NSString *)name ----- 根据名 ...

随机推荐

  1. 手把手教你构建 C 语言编译器

    http://lotabout.me/2015/write-a-C-interpreter-1/

  2. IIS配置支持apk文件下载

    写在前面 最近项目中涉及到移动端的东西,有一个功能是要下载apk文件,apk为安卓安装程序,但是iis默认是不支持该类型的文件下载的. 解决方案 找到该站点,并切换到功能视图 找到MIME类型,双击进 ...

  3. js 拦截全局 ajax 请求

    你是否有过下面的需求:需要给所有ajax请求添加统一签名.需要统计某个接口被请求的次数.需要限制http请求的方法必须为get或post.需要分析别人网络协议等等,那么如何做?想想,如果能够拦截所有a ...

  4. linux基础学习8

      管理主机每天任务: 查询登录档.追踪流量.监控用户使用主机状态.主机各项硬设备状态. 主机软件更新查询.其他使用者要求: 因此shell script 就必须要学啊,虽然可以说绝大部分shell能 ...

  5. 检查iOS app 是否升级为新版本

    之前我帮某公司做的一个iOS app,升级的时候发现闪退问题.后来检查是因为升级的时候数据库出现一点小问题导致对象为空. 下面这个代码可以检测程序是否更新了,从而进行相关处理: 1 2 3 4 5 6 ...

  6. Failed to fetch URL http://dl-ssl.google.com/android/repository/repository.xml, reason:

    Failed to fetch URL http://dl-ssl.google.com/android/repository/repository.xml, reason: Connection t ...

  7. poj 3648 线段树成段更新

    线段树成段更新需要用到延迟标记(或者说懒惰标记),简单来说就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新or询问到的时候.延迟标记的意思是:这个区间的左右儿子都需要被更新,但是当 ...

  8. java基础篇5之泛型

    1 泛型的基本应用 //反射方式 指定类型,就不用强转 Construcctor<String> constructor = String.class.getConstructor(Str ...

  9. 2015年度新增开源软件排名TOP100

    2015年度新增开源软件排名TOP100 本榜单包含2015年开源中国新收录的软件中,根据软件本身的关注度.活跃程度进行排名前100名的软件.从这份榜单中或许可以了解到最新业界的趋势. 1.Switc ...

  10. 【日常学习】【并查集+map】codevs2639 约会计划题解

    然而我居然让诸城一中悲剧机房的C++可以编译了··· 直接上题目 题目描写叙述 Description cc是个超级帅哥,口才又好.rp极高(这句话似乎降rp),又非常的幽默,所以非常多mm都跟他关系 ...