koa-static 实现

前言

狭义中间件 请求/拦截,最典型的场景是 Koa.js 传输静态文件中间件的实现koa-send。Koa.js 官方对 koa-send 进行二次封装,推出了koa-static 中间件,目标是用于做静态服务器或者项目静态资源管理。

本节主要以官方的 koa-static 中间件为参考,基于上一节实现的最简单koa-send, 实现了一个最简单的koa-static 中间件,方便原理讲解和后续二次自定义优化开发。

实现步骤

  • step 01 配置静态资源绝对目录地址
  • step 02 判断是否支持等待其他请求
  • step 03 判断是否为 GET 和 HEAD 类型的请求
  • step 04 通过koa-send 中间件读取和返回静态文件

实现源码

demo源码

https://github.com/chenshenhai/koajs-design-note/tree/master/demo/chapter-04-03

  1. ## 安装依赖
  2. npm i
  3. ## 执行 demo
  4. npm run start
  5. ## 最后启动chrome浏览器访问
  6. ## http://127.0.0.1:3000/index.html

koa-static 依赖

koa-send 中间件,这里只用了上一节实现的最简单koa-send

koa-static 解读

  1. const {resolve} = require('path');
  2. const send = require('./send');
  3. function statics(opts = {
  4. root: ''
  5. }) {
  6. opts.root = resolve(opts.root);
  7. // 是否需要等待其他请求
  8. if (opts.defer !== true) {
  9. // 如果需要等待其他请求
  10. return async function statics(ctx, next) {
  11. let done = false;
  12. if (ctx.method === 'HEAD' || ctx.method === 'GET') {
  13. try {
  14. await send(ctx, ctx.path, opts);
  15. done = true;
  16. } catch (err) {
  17. if (err.status !== 404) {
  18. throw err;
  19. }
  20. }
  21. }
  22. if (!done) {
  23. await next();
  24. }
  25. };
  26. } else {
  27. // 如果不需要等待其他请求
  28. return async function statics(ctx, next) {
  29. await next();
  30. if (ctx.method !== 'HEAD' && ctx.method !== 'GET') {
  31. return;
  32. }
  33. if (ctx.body != null || ctx.status !== 404) {
  34. return;
  35. }
  36. try {
  37. await send(ctx, ctx.path, opts);
  38. } catch (err) {
  39. if (err.status !== 404) {
  40. throw err;
  41. }
  42. }
  43. };
  44. }
  45. }
  46. module.exports = statics;

koa-static 使用

  1. const path = require('path');
  2. const Koa = require('koa');
  3. const statics = require('./index');
  4. const app = new Koa();
  5. const root = path.join(__dirname, './public');
  6. app.use(statics({ root }));
  7. app.use(async(ctx, next) => {
  8. if (ctx.path === '/hello') {
  9. ctx.body = 'hello world';
  10. }
  11. });
  12. app.listen(3000);
  13. console.log('listening on port 3000');

附录

参考