koa2 路由使用入门文档

潘弘壮
2023-12-01

koa-router

Koa 的路由中间件

使用方式

new Router([opts]);

创建一个路由.

选项参数:

  1. opts : Object
  2. opts.prefix : String - 设置路由的前缀

例子:

基本用法:

const Koa = require("Koa");
const Router = require("@koa/router");

// 初始化 koa 实例
const app = new Koa();

// 初始化路由实例
const router = new Router();

// 设置路由
router.get("/", ctx => {
  // ctx.router 可以访问
  // 做一些当前路由的处理
});

// 注册路由中间件
app.use(router.routes()).use(router.allowedMethods());

router.get|put|post|patch|delete|del => Router

创建 router 请求方法, 请求可以是上面的 get|put|post|patch|delete|del 之一, 比如 router.get()router.post()

路由请求中的第一个参数, 如 / 会和 URL 模式进行匹配, 如果匹配成功就掉对应的 回调函数控制器 对路由请求进行处理。

router.all() 会匹配所有的请求方法。

router
  .get("/", (ctx, next) => {
    ctx.body = "Hello,World";
  })
  .post("/users", (ctx, next) => {
    // ...
  })
  .put("/users/:id", (ctx, next) => {
    // ...
  })
  .del("/users/:id", (ctx, next) => {
    // ...
  })
  .all("/users/:id", (ctx, next) => {
    ctx.body = ctx.params;
  });

如果路径匹配时, 它的路径在 ctx._matchedRoute 可访问, 如果命名, 则名称在 ctx._matchedRouteName 中可用。

路由路径将被转换为正则表达式, 使用到的转换库是 path-to-regexp的规则。

匹配请求时暂时将不考虑查询字符串。

命名路由

路由可以选择有名称。这允许生成 URL 并在开发过程中轻松重命名 URL, 方便在开发过程中使用和通过 ctx._matchedRouteName 来访问当前路由器的名称。

router.get("user", "/users/:id", ctx => {
  console.log(ctx._matchedRouteName); // user
  ctx.body = ctx.params;
});

多个中间件

可以给当前路由匹配, 提供多个中间件函数。

router.get(
  "/users/:id",
  async (ctx, next) => {
    if (ctx.params.id === "1") {
      await next();
    } else {
      ctx.status = 401;
      ctx.body = "无权访问";
    }
  },
  ctx => {
    ctx.body = ctx.params;
  }
);

可以做一些权限校验等, 这个路由内部 Layer 是横向存储中间件的。

嵌套路由

支持嵌套路由

// 论坛路由实例
const forums = new Router();
// 帖子路由实例
const posts = new Router();

posts.get("/", (ctx, next) => {
  ctx.body = ctx.request.url;
});

posts.get("/:pid", (ctx, next) => {
  ctx.body = {
    url: ctx.request.url,
    params: ctx.params
  };
});

// 注册嵌套路由
forums.use("/forums/:fid/posts", posts.routes(), posts.allowedMethods());

// 注册路由中间件
app.use(forums.routes());

路由器前缀

路由路径可以在路由器级别加上前缀。

// 初始化路由实例
const router = new Router({
  prefix: "/users"
});

router.get("/", ctx => {
  ctx.body = ctx.url;
});

router.get("/:id", ctx => {
  ctx.body = ctx.params;
});

// 注册路由中间件
app.use(router.routes()).use(router.allowedMethods());

URL 参数

动态路由会通过正则匹配到值后, 将作为 keyvalue 的形式添加到 ctx.params 属性上。

router.get("/:category/:title", (ctx, next) => {
  console.log(ctx.params);
  // => { category: 'programming', title: 'how-to-node' }
});

path-to-regexp 模块用于将路径转换成正则表达式。

router.routes() => Function

返回分配给与请求匹配的路由的路由器中间件。

router.use([path], middleware) => Router

使用给定的中间件

中间件按照 .use() 定义的顺序运行。它们是按顺序调用的, 请求从第一个中间件开始, 并按照中间件栈的方式工作。

// session 中间件会在 authorize 中间件之前执行
router.use(session()).use(authorize());

// 仅在给定路径下使用中间件
router.use("/users", userAuth());

// 在 /users 或 /admin 路径下调用 userAuth 中间件
router.use(["/users", "/admin"], userAuth());

app.use(router.routes());

router.prefix(prefix) => Router

为已经初始化的路由器实例设置路径前缀

// 初始化路由实例
const router = new Router().prefix("/users");

router.get("/", ctx => {
  ctx.body = ctx.url;
});

router.get("/:id", ctx => {
  ctx.body = ctx.params;
});

// 注册路由中间件
app.use(router.routes()).use(router.allowedMethods());

router.allowedMethods([options]) => Function

返回单独的中间件函数, 用于处理响应选项请求, 其中包含允许的方法和运行的头部字段。

例子

const Koa = require("koa");
const Router = require("@koa/router");

const app = new Koa();
const router = new Router();

app.use(router.routes());
app.use(router.allowedMethods());

或者

const Koa = require("koa");
const Router = require("@koa/router");
const Boom = require("boom");

const app = new Koa();
const router = new Router();

app.use(router.routes());
app.use(
  router.allowedMethods({
    throw: true,
    notImplemented: () => new Boom.notImplemented(),
    methodNotAllowed: () => new Boom.methodNotAllowed()
  })
);

router.redirect(source, destination, [code]) => Router

用可选的 30x 状态代码重定向 sourcedestination 路径。

sourcedestination 都可以是路由名称。

// 初始化路由实例
const router = new Router();

router.get("/", ctx => {
  ctx.body = "Hello";
});

router.get("about", "/about", ctx => {
  ctx.body = "重定向到了这里";
});

router.redirect("/user", "about");

// 注册路由中间件
app.use(router.routes()).use(router.allowedMethods());

router.route(name) => Layer | false

通过名字搜索路由

// 初始化路由实例
const router = new Router();

router.get("/", ctx => {
  ctx.body = "Hello";
});

router.get("about", "/about", ctx => {
  ctx.body = "重定向到了这里";
});

router.redirect("/user", "about");

console.log(router.route("about"));

/**
 Layer {
  opts: {
    end: true,
    name: 'about',
    sensitive: false,
    strict: false,
    prefix: '',
    ignoreCaptures: undefined
  },
  name: 'about',
  methods: [ 'HEAD', 'GET' ],
  paramNames: [],
  stack: [ [Function] ],
  path: '/about',
  regexp: /^\/about(?:\/(?=$))?$/i { keys: [] }
}
 */

router.url(name, params, [options]) => String | Error

生成路由 URL, 获取命名为 params 的路由名称和地图

router.get("user", "/users/:id", (ctx, next) => {
  // ...
});

router.url("user", 3);
// => "/users/3"

router.url("user", { id: 3 });
// => "/users/3"

router.use((ctx, next) => {
  // redirect to named route
  ctx.redirect(ctx.router.url("sign-in"));
});

router.url("user", { id: 3 }, { query: { limit: 1 } });
// => "/users/3?limit=1"

router.url("user", { id: 3 }, { query: "limit=1" });
// => "/users/3?limit=1"
 类似资料: