koa-static 源码分析

koa-static

koa-static是 koa 的静态文件服务中间件

Example

1
2
3
4
5
6
7
const koaStatic = require('koa-static');

app.use(koaStatic({
path.resolve(__dirname, '../static');
}, {}));

app.listen(8888);

比如你的static文件目录结构为

1
2
3
4
├── html
│ └── upfile.html
└── uploads
│ └── aa.js

那就可以通过浏览器访问http://localhost:8888/html/upfile.html访问静态文件了

options

截取自koa-staticgithub readme 的常用 options

  • maxage Browser cache max-age in milliseconds. defaults to 0
  • hidden Allow transfer of hidden files. defaults to false
  • index Default file name, defaults to ‘index.html’
  • defer If true, serves after return next(), allowing any downstream middleware to respond first.
  • gzip Try to serve the gzipped version of a file automatically when gzip is supported by a client and if the requested file with .gz extension exists. defaults to true.
  • [setHeaders] Function to set custom headers on response.
  • extensions Try to match extensions from passed array to search for file when no extension is sufficed in URL. First found is served. (defaults to false)

源码分析

koa-static依赖koa-send包, 大部分逻辑都是koa-send处理的, koa-static只对options.defer做了处理.

  • defer 顾名思义, 如果为true, 则先执行koa-send, 找到文件直接返回, 否则await next(); false则相反, 先await next(), ctx.body如果还是null则执行koa-send

koa-send核心逻辑通过path.resolvePath(ctx.path)和初始化时的 root 路径拼接得到文件在服务端的真实文件路径, 最后以 readable stream 的形式返回

1
ctx.body = fs.createReadStream(path);

koa 中同样对 stream 类型的数据做了处理, 通过pipe管道返回给浏览器数据

1
2
3
4
5
// application.js
// responses
if (Buffer.isBuffer(body)) return res.end(body);
if ('string' === typeof body) return res.end(body);
if (body instanceof Stream) return body.pipe(res);

koa-static也通过fs.stat获取文件的具体信息设置响应头

1
2
3
4
5
6
7
ctx.set('Content-Length', stats.size)

if (!ctx.response.get('Last-Modified')) ctx.set('Last-Modified', stats.mtime.toUTCString())
}

if (!ctx.type) ctx.type = type(path, encodingExt)

对 option.setHeader 的处理

1
if (setHeaders) setHeaders(ctx.res, path, stats);

对 option.hidden 的处理, 这里 option.hidden 为 true 以及文件名以.开头都是会隐藏的, isHidden函数判断文件名是否为.xxx

1
2
// hidden file support, ignore
if (!hidden && isHidden(root, path)) return;

对 option.extensions 的处理, 设置了 extensions 数组则允许浏览器 url 不带上后缀

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if (extensions && !/\./.exec(basename(path))) {
const list = [].concat(extensions);

for (let i = 0; i < list.length; i++) {
let ext = list[i];

if (typeof ext !== 'string') {
throw new TypeError('option extensions must be array of strings or false');
}

if (!/^\./.exec(ext)) ext = `.${ext}`;

if (await exists(`${path}${ext}`)) {
path = `${path}${ext}`;

break;
}
}
}

koa-static 源码分析
https://mariana-yui.github.io/2022/08/20/2022-08-20-koa-static/
作者
Mariana
发布于
2022年8月20日
许可协议