koa 中间件

Posted twinkle||cll

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了koa 中间件相关的知识,希望对你有一定的参考价值。

koa 是一个轻量级(对比express 区别请查看我上一篇文章web 服务的框架,里面没有自带的中间件,因此我们需要来自己实现中间件或者使用第三方人家开发好的中间件。

在写一个服务端应用的时候,一般都会使用到作为静态服务器,node 搭建静态服务请查看我以前文章,express中间件实现静态资源服务的话可以使用 express.static()来实现,那么koa如何实现呢? 其实对于一个静态服务的话,只要你会node这个底层的原理,express 或者 koa 这些上层应用都是基于底层原理来的

步骤

  1. 获取路径的path,作为服务的话,需要提供一个根路径和静态资源的目录;
  2. 判断提供的path 是文件夹、文件或者不存在;
  3. 去读指定文件的内容,设置响应头;
  4. 给浏览器返回一个文件内容

代码如下:

const path = require('path');
const fs = require('fs')
// 这里使用mime 这个库来判断文件的类型,从而设置响应头
const mime = require('mime');
/**
 * 获取文件名称
 * @param {*} filename 
 * @param {*} root 
 * @returns 
 */
async function getFileName(filename, root) {
  // 获取文件的全路径,node 中规定,如果是以 \\ 开头,就是绝对路径是一个跟路径
  const fullName = path.resolve(root, filename.substring(1));
  // 判断当前路径是文件还是文件夹或者不存在
  try {
    const fsStat = await fs.promises.stat(fullName);
    if (fsStat.isDirectory()) {
      // 如果是目录的话,那就需要补上默认文件
      const adtFileName = path.join('/index.html');
      return await getFileName(adtFileName, root);
    } else {
      return fullName;
    }
  } catch (error) {
    return null;
  }
}

/**
 * 读取静态资源目录
 * @param {*} root 
 * @returns 
 */
module.exports = function (root) {
  return async (ctx, next) => {
    if (ctx.method !== 'GET') {
      await next();
      return;
    }
    const filename = await getFileName(ctx.path, root)
    if (!filename) {
      // 文件不存在
      await next();
      return;
    }
    // 根据文件的后缀名响应文件
    const mimeType = mime.getType(filename);
    // 返回一个文件流
    ctx.body = fs.createReadStream(filename);
    // 设置文件的类型
    ctx.type = mimeType;
    await next();
  }
}
复制代码

手动实现 connect-history-api-fallback 中间件

单页应用中,我们会使用路由的history模式,刷新浏览器的时候,需要重新回到index.html页面,这个中间件在koa 中怎么实现呢?connect-history-api-fallback官网告诉我们有几个匹配规则,如下:

规则

image.png ``

  1. 只能匹配get请求
  2. 请求的header 的文件类型是text/html
  3. 请求不是一个重定向的请求,请求的path中不能包含·,因为带点的就意味着是请求的是一个静态资源,如,js,css,图片等

代码

module.exports = async function (ctx, next) {
  // 判断当前请求是不是get请求,请求的路径中是否包含.,并且请求头的类型是html文件
  if (ctx.method === "GET" &&
    ctx.headers.accept.includes("text/html") &&
    !ctx.path.includes(".")) {
    ctx.path = '/index.html'
  }
  await next();
}
复制代码

这个地方有一个小插曲,那就是,在使用静态资源的时候,需要使用绝对路径,不能使用相对路径,不然静态资源会不对,你可以打开单页应用打的包的路径绝对是以/开头的(前提是history模式的路由,hash路由也不会使用这个插件)。

image.png

常用KOA中间件

Koa中间件功能
@koa/router官方中间件。借鉴了koa-router
用于处理路由的中间件,用法类似 express.Router
koa-bodyparser解析请求体的中间件,支持
x-www-form-urlencoded, application/json格式的请求体
koa-views渲染模板引擎的中间件,一般用于传统的服务端渲染
koa-static用于搭建静态资源服务器的中间件
koa-static-cache实现了http缓存的静态资源中间件
koa-sessionsession中间件
koa-jwt支持jwt的中间件
koa-compress支持gzip动态压缩的中间件
koa-logger日志记录中间件
@koa/cors官方中间件。支持CORS跨域的中间件
@koa/multer官方中间件,借鉴了koa-multer
用户处理文件上传的中间件
koa-connect将express或connect中间件转换为koa中间件
http-proxy-middleware代理中间件(这个中间件需要使用koa-cennect后才可以使用)
connect-history-api-fallback单页应用支持
(这个中间件需要使用koa-cennect后才可以使用)
koa-convert用于将旧版本的koa中间件转换为koa2中间件

以上是关于koa 中间件的主要内容,如果未能解决你的问题,请参考以下文章

koa2-6

koa与express的中间件机制揭秘

Koa中间件(middleware)级联原理

koa中间件实现分析

Koa答疑,你见过同步的Node.js代码么?

node.js Koa 框架 的中间件用法