手写koa-static源码,深入理解静态服务器原理

这篇文章继续前面的Koa源码系列,这个系列已经有两篇文章了:

  1. 第一篇讲解了Koa的核心架构和源码:手写Koa.js源码
  2. 第二篇讲解了@koa/router的架构和源码:手写@koa/router源码

本文会接着讲一个常用的中间件----koa-static,这个中间件是用来搭建静态服务器的。

其实在我之前使用Node.js原生API写一个web服务器已经讲过怎么返回一个静态文件了,代码虽然比较丑,基本流程还是差不多的:

  1. 通过请求路径取出正确的文件地址
  2. 通过地址获取对应的文件
  3. 使用Node.js的API返回对应的文件,并设置相应的header

koa-static的代码更通用,更优雅,而且对大文件有更好的支持,下面我们来看看他是怎么做的吧。本文还是采用一贯套路,先看一下他的基本用法,然后从基本用法入手去读源码,并手写一个简化版的源码来替换他。

基本用法

koa-static使用很简单,主要代码就一行:

const Koa = require('koa');
const serve = require('koa-static');

const app = new Koa();

// 主要就是这行代码
app.use(serve('public'));

app.listen(3001, () => {
   
    console.log('listening on port 3001');
});

上述代码中的serve就是koa-static,他运行后会返回一个Koa中间件,然后Koa的实例直接引用这个中间件就行了。

serve方法支持两个参数,第一个是静态文件的目录,第二个参数是一些配置项,可以不传。像上面的代码serve('public')就表示public文件夹下面的文件都可以被外部访问。比如我在里面放了一张图片:

image-20201125163558774

跑起来就是这样子:

image-20201125163432769

注意上面这个路径请求的是/test.jpg,前面并没有public,说明koa-static对请求路径进行了判断,发现是文件就映射到服务器的public目录下面,这样可以防止外部使用者探知服务器目录结构。

手写源码

返回的是一个Koa中间件

我们看到koa-static导出的是一个方法serve,这个方法运行后返回的应该是一个Koa中间件,这样Koa才能引用他,所以我们先来写一下这个结构吧:

module.exports = serve;   // 导出的是serve方法

// serve接受两个参数
// 第一个参数是路径地址
// 第二个是配置选项
function serve(root, opts) {
   
    // 返回一个方法,这个方法符合koa中间件的定义
    return async function serve(ctx, next) {
   
        await next();
    }
}

调用koa-send返回文件

现在这个中间件是空的,其实他应该做的是将文件返回,返回文件的功能也被单独抽取出来成了一个库----koa-send,我们后面会看他源码,这里先直接用吧。

function serve(root, opts) {
   
    // 这行代码如果效果就是
    // 如果没传opts,opts就是空对象{}
    // 同时将它的原型置为null
    opts = Object.assign(Object.create(null), opts);

    // 将root解析为一个合法路径,并放到opts上去
    // 因为koa-send接收的路径是在opts上
    opts.root = resolve(root);
  
  	// 这个是用来兼容文件夹的,如果请求路径是一个文件夹,默认去取index
    // 如果用户没有配置index,默认index就是index.html
    if (opts.index !== false) opts.index = opts.index || 'index.html';

  	// 整个serve方法的返回值是一个koa中间件
  	// 符合koa中间件的范式: (ctx, next) => {}
    return async function serve(ctx, next) {
   
        let done = false;    // 这个变量标记文件是否成功返回

        // 只有HEAD和GET请求才响应
        if (ctx.method === 'HEAD' || ctx.method === 'GET') {
   
            try {
   
                // 调用koa-send发送文件
                // 如果发送成功,koa-send会返回路径,赋值给done
                // done转换为bool值就是true
                done = await send(
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值