Koa2框架路由应用,Koa2前景、Koa2中间件

发布时间 2023-09-28 16:50:19作者: 漫思

Koa2框架路由应用,Koa2前景、Koa2中间件

 
展开目录
 

本文内容:

1、Koa2框架是什么?Koa框架教程快速入门Koa中间件

2、Koa2框架路由应用,Koa2前景、Koa2中间件

3、Koa2异常处理

1、路由简介

我们知道一个系统中有很多的页面,要想访问系统中的不同页面需要在浏览器的地址栏中输入不同的URL地址,然后Koa接收到对应的请求后根据不同的URL地址来决定到底访问哪个页面,而这就是Koa中路由的作用。也就是说路由决定了不同的URL是如何被执行的。如果没有路由,我们在浏览器中不管输入什么样的URL地址,返回的都是相同的内容。

所以说,路由存在的意义:

第一:可以处理不同的URL

第二:处理不同的HTTP请求的方法(例如,post,get等等),因为针对不同URL地址,请求的方式有可能是不同的,有可能是get请求,也有可能是post请求,所以就需要路由能够处理不同的HTTP 请求的方法。

第三:解析URL上的参数。通过前面Node.js课程的学习,我们知道URL地址中经常需要带上参数,例如:/index/1, 所以路由必须能够解析URL上的参数。

了解了什么是路由后,下面我们来学习一些路由的基本使用。

2、路由基本使用

Koa中路由其实就是一个中间件,那么接下来我们就自己编写一个路由的中间件(如果关于中间件不熟悉,请学习Koa2快速入门课程,该课程中有关于中间件的详细讲解)。

在学习路由简介的时候,我们知道路由的功能有如下三点:

第一:处理不同的URL,

第二:处理不同的HTTP请求的方法

第三:解析URL上的参数。

下面,我们来看一下第一个功能,处理不同的URL。具体的要求如下:

如果用户在浏览器中输入的URL地址为/, 返回的内容是"这是首页"这个字符串,如果用户在浏览器中输入的URL地址为/about,返回的内容是“这是关于页面”。

核心的实现思路:首先,先接收用户请求的URL值,这就需要用到Koa中的上下文对象(关于上下文对象在Koa2入门课程中有讲解),然后根据接收到的URL地址进行判断,来决定显示什么内容。

具体的实现代码如下(这里我们在项目中又新建了一个routerDemo.js文件来实现本案例):

const Koa=require('Koa')
const app=new Koa();
app.use(async(ctx,next) =>{
    if(ctx.url==='/'){
        ctx.body='这是首页'
    }else if(ctx.url==='/about'){
        ctx.body='这是关于页面'
    }else{
        ctx.status=404;
    }
})
app.listen("3000", () => console.log("服务端启动"));

在上面的代码中,我们实现了一个中间件,并且通过上下文对象ctx中的url属性,可以获取到浏览器所请求的URL地址,然后根据获取到的URL地址进行判断,如果是/,则通过ctx.body返回给浏览器的内容是"这是首页",如果获取到的URL地址为/about,则通过ctx.body返回给浏览器的内容是“这是关于页面”。

下面,通过命令:

node routerDemo.js

启动上面的程,如下图所示:

现在,服务端已经启动起来了,下面打开浏览器,输入不同的URL地址看一下执行效果,效果如下图所示:

动图封面
 

通过上图,我们可以看到在浏览器的地址栏中输入http://localhost:3000/ ( 端口号后面的/会自动去掉 ) 时,显示的内容是"这是首页",当输入的地址为:http://localhost:3000/about时,显示的内容为"这是关于页面"。

这样我们就完成了处理不同URL的功能。

下面,我们再来看一下怎样处理不同的HTTP请求的方法。

具体的要求如下:

如果用户请求的地址为/login, 在这会返回一个登录的表单,然后用户在表单中输入用户名和密码后,单击登录按钮,这时发送的请求方式为post,

那么对应的在服务端可以通过上下文对象中的method属性来接收请求的方式,并对请求方式作出一个判断,如果为post请求,那么可以接收传递过来的用户名和密码,并将其打印出来。

核心的实现思路: 如果用户请求的地址为/login,这里需要返回一个登录的表单,关于表单中的内容我们可以单独的写到一个html文件中,然后通过fs模块中的createReadStream进行读取, 将读取后的表单内容返回给浏览器,同时当用户单击了表单中的登录按钮的时候,这里需要判断请求的方式是否为post,所以需要用到上下文的method属性。如果判断的结果为post,需要接收提交过来的用户名与密码,那么对应的就需要对表单内容进行解析,这里用到的是koa-bodyparser这个中间件,该中间件的安装指令如下:

npm install koa-bodyparser

下面看一下具体代码的实现:

const Koa = require("Koa");
const app = new Koa();
// 导入fs模块
const fs = require("fs");
// 导入koa-bodyparser中间件解析表单内容
const bodyParser = require("koa-bodyparser");
// 使用 koa-bodyparser中间件。
app.use(bodyParser());
// 模拟用户登录
app.use(async (ctx, next) => {
  if (ctx.url === "/login") {
    //   指定返回文件类型
    ctx.type = "html";
    //读取login.html文件内容
    ctx.body = fs.createReadStream("./login.html");
  } else if (ctx.url === "/userLogin") {
    //判断请求方式是否为:'GET'
    if (ctx.method === "GET") {
      ctx.body = "请求方式为GET";
    } else if (ctx.method === "POST") {
      //如果请求方式为:'POST',则获取表单中用户输入的用户名与密码。
      ctx.body ="用户名是:" + ctx.request.body.userName + ",密码是:" +ctx.request.body.userPwd;
    } else {
      ctx.body = "请求方式错误";
    }
  } else {
    ctx.body = "请求页面不存在!!";
  }
});
app.listen("3000", () => console.log("服务端启动"));

下面我们对上面这段代码做一个分析。

最开始我们导入了fs模块以及koa-bodyparser中间件,然后在模拟用户登录的这个中间件中,先判断请求的地址是否为/login,如果是通过fs模块中的createReadStream 方法读取login.html文件内容并返回给浏览器,这里需要注意的是,需要指定返回的文件类型为html.

如果请求的地址不是/login,那么判断一下是否为/userLogin,如果是,表明用户单击了表单中的登录按钮。那么接下来要接收用户名与密码。在接收用户名与密码之前,还需要判断请求的方式。如果是GET请求,返回的内容是“请求方式为GET”,如果是POST请求,则接收传递的用户名与密码(因为表单的提交方式为'POST')。

关于用户名与密码的接收,这里使用的还是上下文对象ctx,通过该对象中request中的body属性来接收传递过来的用户名与密码。那么,这里怎样区分接收到的是用户名还是密码呢?就需要用根据表单元素的name属性值来区分了,用户名对应的表单元素是一个文本框,它的name属性取值为userName,密码对应的表单元素是一个密码框,它的name属性取值为userPwd(这里可以通过下面所展示的登录表单进行查看).最后将接收到的用户名与密码返回给浏览器进行展示。

当然,如果判断的请求方式既不是GET也不是POST,这里会给出“请求错误”的提示。

最后,我们也可以看到,如果请求的地址不是/login也不是/userLogin,会给出请求页面不存在的提示。

关于登录表单login.html中的代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>登录</title>
</head>
<body>
    <form method="post" action="/userLogin">
        用户名:<input type="text" name="userName"/><br />
        密码<input type="password" name="userPwd"/><br />
        <input type="submit" value="登录"/>
    </form>
</body>
</html>

在这里,可以看到当用户单击“登录”按钮后,提交的方式为post提交,同时指定的请求地址为/userLogin. 而且用户名这个文本框中的name属性取值为userName,密码框的name取值为userPwd.

下面,将程序运行起来 ,看一下运行的效果。

动图封面
 

通过上面的截图,我们可以看到当在浏览器的地址栏中输入http://localhost:3000/login时,展示出了一个登录表单。然后在该表单中输入用户名与密码,单击登录按钮,这时会向服务端发送post请求,并将用户名与密码发送到服务端,服务端接收过来后,又返回到浏览器端进行展示。最后,如果输入的URL地址是不存在的,则在浏览器中展示"请求页面不存在!!"

以上就是路由对请求方式的处理。

下面看一下,怎样解析URL上的参数。

在这里我们可以用我们前面所学习的正则表达式来解决这个问题。

如下代码:

const Koa = require("Koa");
const app = new Koa();
app.use(async (ctx, next) => {
  if (ctx.url.match(/\/users\/\w+/)) {
    const userId = ctx.url.match(/\/users\/(\w+)/)[1];//获取数字
    ctx.body = "用户编号为" + userId;
  }
});
app.listen("3000", () => console.log("服务端启动"));

在上面的代码中 ,我们使用了正则表达式来判断请求的URL地址,以及对参数进行处理。在这,我们判断一下请求的URL地址中,是否含有/users 并且是否后面跟有数字,例如:/users/1. 如果符合这种格式要求,就获取后面的数字,而该数字就是通过URL 传递过来的参数。

运行上面的程序看一下效果,效果如下图所示:

动图封面
 

通过上图,可以看到在地址栏中输入http://localhost/users/1,我们就可以获取到对应的参数1,然后返回给浏览器进展示。

以上就是关于路由基本使用的内容,在这我们就学习完了,下面对这块内容来做一个总结:

路由决定了不同的URL是如何被执行的,它的主要功能有如下三点:

第一:处理不同的URL,

第二:处理不同的HTTP请求的方法

第三:解析URL上的参数。

在处理不同的URL时,我们主要到了上下文对象ctx中的url属性,根据该属性来获取用户所请求的URL地址。

关于处理不同的HTTP请求的方法,这里使用了上下文对象ctx中的method属性,该属性可以获取请求的方式,例如:POST请求,GET请求等。

当然在对表单发送POST请求后,服务端需要用koa-bodyparser中间件来对提交过来的数据进行解析处理。

关于解析URL上的参数,这里主要是使用了正则表达式来完成。

在学习下一小节内容前,需要你思考如下问题的实现。

根据不同的URL地址请求,返回不同的页面。例如,用户请求的URL地址是/index,返回的是index.html页面的内容,如果请求的是/list返回的就是list.html页面的内容。

思路分析 :通过上下文对象ctx中的url属性获取请求的URL地址,然后进行判断,从而决定要读取哪个文件内容,返回给浏览器。

参考代码如下:

 

const Koa = require("koa");
const fs = require("fs");
const app = new Koa();
// fileName:表示文件名
function render(fileName) {
  return new Promise((resolve, reject) => {
    let viewUrl = `./view/${fileName}`;
    fs.readFile(viewUrl, (err, data) => {
      if (err) {
        reject(err);
      } else {
        resolve(data);
      }
    });
  });
}
/**
 url:请求的URL地址
 */
async function route(url) {
  let fileName = "list.html";
  switch (url) {
    case "/":
      fileName = "index.html";
      break;
    case "/index":
      fileName = "index.html";
      break;
    case "/user":
      fileName = "user.html";
      break;
    case "/list":
      fileName = "list.html";
      break;
    default:
      break;
  }
  let html = await render(fileName);
  return html;
}
app.use(async (ctx, next) => {
  let url = ctx.url;
  let content = await route(url);
  ctx.type = "html";
  ctx.body = content;
});
app.listen("3000", () => console.log("服务端启动"));

下面对上面的代码做一个分析:

在上面的代码中,我们自己定义了一个中间件,如下所示:

app.use(async (ctx, next) => {
  let url = ctx.url;
  let content = await route(url);
  ctx.type = "html";
  ctx.body = content;
});

在上面的中间件中接收浏览器发送过来的请求,并且通过ctx.url获取到请求的URL地址,然后将获取到的URL地址传递到route方法中, 该方法的作用就是根据传递过来的URL地址,找到对应的html网页文件,然后进行读取操作。最后定义content变量来接收route方法返回的内容,也就是读取到的html文件内容,交给ctx.body返回给浏览器。

下面我们在看一下route方法的具体实现,如下代码所示:

async function route(url) {
  let fileName = "list.html";
  switch (url) {
    case "/":
      fileName = "index.html";
      break;
    case "/index":
      fileName = "index.html";
      break;
    case "/user":
      fileName = "user.html";
      break;
    case "/list":
      fileName = "list.html";
      break;
    default:
      break;
  }
  let html = await render(fileName);
  return html;
}

通过上面的代码,我们可以很清楚的看到在route方法中,首先会根据传递过来的url地址,指明要操作的是哪个文件,这里使用了switch进行判断。

然后找到要操作的html文件后,将文件名赋值给了fileName这个变量,最后将该变量传递到了render 方法中,那么你可以想一下render方法的主要作用是什

么?对了,就是根据传递过来的文件名,找到该文件,进行读取。

代码 如下所示:

function render(fileName) {
  return new Promise((resolve, reject) => {
    let viewUrl = `./view/${fileName}`;
    fs.readFile(viewUrl, (err, data) => {
      if (err) {
        reject(err);
      } else {
        resolve(data);
      }
    });
  });
}

我们可以看到在render 方法中返回的是一个Promise对象。在该对象的回调函数中,我们根据传递过来的文件名,从view这个文件夹下找到具体的文件,然后使用readFile方法来读取该文件,如果在读取的过程中出现了错误,使用reject返回,如果没有错误就使用resolve返回读取的内容。这样在route方法中,我们借助于await可以获取到具体的文件内容,如下代码:

  let html = await render(fileName);

通过上面的代码,可以看到我们将文件读取,以及URL路径的判断都封装到了不同的函数中,这样职责更加的明确。

下面看一下项目的结构图:

通过上面这张图可以看到,我们在view目录下面创建了html文件,然后在routerDemo.js 文件中实现上面的代码。

下面我们再看一下整个程序的运行效果:

动图封面
 

通过上图可以看到,我们最终实现了我们想要的效果。

3、koa-router基本使用

在上一小节中虽然实现了路由的一些操作,但是实现起来比较麻烦,并且代码不够美观。为了解决这个问题,我们可以使用koa-router这个中间件来解决。

下面我们就来学习一下koa-router这个中间件的应用。

首先,先安装koa-router中间件。

npm i koa-router --save

基本使用的代码如下所示(在koaRouterDemo.js文件中进行编写):

const Koa=require('Koa')
// 导入koa-router
const Router=require('koa-router')
const app=new Koa();
// 创建路由对象
const router=new Router();
const fs=require('fs')
const bodyParser = require('koa-bodyparser');
app.use(bodyParser());
// 使用路由中间件
app.use(router.routes());
router.get('/',(ctx)=>{
    ctx.body='这是首页Home'
})
router.get('/login',(ctx)=>{
    ctx.type='html'
    ctx.body=fs.createReadStream('./login.html')
})
router.post('/userLogin',(ctx)=>{
    ctx.body='用户名是:'+ctx.request.body.userName
})
router.get('/users/:id',(ctx)=>{
    ctx.body='这是用户的编号:'+ctx.params.id
})
app.listen("3000", () => console.log("服务端启动"));

接下来我们对上面的代码做一个分析。首先我们可以看到,在上面的代码中,先导入了koa-router这个路由中间件,并创建出对应的路由对象,然后通过app.use()方法去使用该路由中间件对象(注意:这里需要使用路由中间件对象调用routes方法)。

代码如下:

// 导入koa-router
const Router=require('koa-router')
// 创建路由对象
const router=new Router();
// 使用路由中间件
app.use(router.routes());

在我们所创建的路由对象router中,封装了很多常见的请求的方法,例如:get,post.

如果我们请求某个URL地址时,请求的方式为get,那么对应的就使用路由对象router中的get方法来进行处理,例如上面代码中的/login这个地址,很明显我们请求这个地址的时候,采用的请求方式为get请求,所以这里就通过router对象中的get方法进行处理,get方法有两个参数,第一个参数为请求的URL地址,第二个参数是一个函数,在这个函数中做详细的处理,该函数的参数是上下文对象。也就是说如果我们以get请求的方式来访问'/login'这个地址,那么就会发现,与下面所定义的路由规则是完全匹配的(如下代码所示)。

router.get('/login',(ctx)=>{
    ctx.type='html'
    ctx.body=fs.createReadStream('./login.html')
})

匹配上对应的路由规则(请求方式为get,并且请求的地址为/login),这时就会自动调用router对象中的get方法的第二个参数。第二个参数是一个函数,在这个函数中读取了login.html这个文件中的内容,并且通过ctx.body返回给浏览器。

如果请求的方式为post方式,并且请求的URL地址为/userLogin, 那么就会执行如下代码

router.post('/userLogin',(ctx)=>{
    ctx.body='用户名是:'+ctx.request.body.userName
})

通过上面代码。我们可以看到post方法也有两个参数,第一个参数为请求的URL地址,第二个参数也是一个函数,在该函数中完成具体详细的处理操作。

也就是说,如果我们以post请求的方式去访问/userLogin这个地址,就会匹配上上面所定义的路由规则,这时就会自动的执行post方法的第二个参数,

在这个参数也就是这个函数内,通过上下文对象ctx接收表单中提交过来的用户名,然后交给ctx.body属性,返回给浏览器进行展示。

通过上面的分析,我们可以看到koa-router 这个路由中间件已经完成了我们前面所说的路由很重要的两点功能:

第一:处理不同的URL,

第二:处理不同的HTTP请求的方法

而且在这通过上面的代码,我们也可以很深刻的体会到,通过koa-router这个路由中间件来处理以上两点内容是非常简单的。

那么在这你可能会问了,我们前面讲过路由还有一个非常重要的功能就是“解析URL上的参数”,以前我们是通过正则表达式来完成的,那么koa-router这个路由中间件是怎样“解析URL上的参数”呢?

我们可以看一下如下代码:

router.get('/users/:id',(ctx)=>{
    ctx.body='这是用户的编号:'+ctx.params.id
})

在上面的代码中,如果请求的方式为get,并且请求的地址格式为:/users/参数,例如:/users/1, 就会匹配上上面所定义的路由规则,这时id这个变量中存储的就是数字1(注意id前面有一个冒号).然后自动调用get方法的第二个参数,在第二个参数也就是这个箭头函数中,可以通过上下文对象ctx中的params来获取id这个变量中存储的值。

以上就是koa-router这个路由中间件对URL参数的解析处理。

下面我们来看一下运行的效果,效果如下图所示:

动图封面
 

通过上图可以看到,根据输入不同的URL地址,展示出了不同的内容。

关于koa-router路由中间件的基本使用,在这我们就学习完了,下面对这块内容做一个总结:

在使用koa-router中间件之前,先进行安装,安装的指令如下:

npm i koa-router --save

基本使用代码如下:

// 导入koa-router
const Router=require('koa-router')
// 创建路由对象
const router=new Router();
// 使用路由中间件
app.use(router.routes());

在所创建的路由对象中,封装了很多常见的请求的方法,例如get,post等.可以根据这些方法来处理不同的请求方式。例如如下代码所示:

router.get('/login',(ctx)=>{
    ctx.type='html'
    ctx.body=fs.createReadStream('./login.html')
})

在上面的代码中,定义了一个路由规则,请求的方式为get,请求的地址为/login, 如果符合这个规则,将自动调用get方法的第二个参数,也就是一个箭头函数,在该函数中完成具体的处理任务。

关于对URL参数解析的代码如下:

router.get('/users/:id',(ctx)=>{
    ctx.body='这是用户的编号:'+ctx.params.id
})

如果请求的方式为get,并且请求的地址格式为:/users/参数,例如:/users/1, 就会匹配上上面所定义的路由规则,这时id这个变量中存储的就是数字1(注意id前面有一个冒号).然后自动调用get方法的第二个参数,在第二个参数也就是这个箭头函数中,可以通过上下文对象ctx中的params来获取id这个变量中存储的值。

在学习下一小节内容前,先来思考回答如下问题:

根据不同的URL地址请求,返回不同的页面。例如,用户请求的URL地址是/index,返回的是index.html页面的内容,如果请求的是/list返回的就是list.html页面的内容。

关于上面这个问题,我们在第二小节的课程中做过,现在这里需要你使用koa-router这个路由中间件来实现一下。

思路分析 :实现的思路与第二小节实现思路基本一致,只不过这里不要在定义单独的一个方法来对请求的URL地址进行判断。

实现代码如下:

const Koa = require("Koa");
// 导入koa-router
const Router = require("koa-router");
const app = new Koa();
// 创建路由对象
const router = new Router();
const fs = require("fs");
const bodyParser = require("koa-bodyparser");
app.use(bodyParser());
// 使用路由中间件
app.use(router.routes());
//读取文件内容, fileName:表示文件名
function render(fileName) {
  return new Promise((resolve, reject) => {
    let viewUrl = `./view/${fileName}`;
    fs.readFile(viewUrl, (err, data) => {
      if (err) {
        reject(err);
      } else {
        resolve(data);
      }
    });
  });
}


router.get("/", async (ctx) => {
  ctx.type = "html";
  let content = await render("index.html");
  ctx.body = content;
});
router.get("/list", async (ctx) => {
  ctx.type = "html";
  ctx.body = await render("list.html");
});
router.get("/user", async (ctx) => {
  ctx.type = "html";
  ctx.body = await render("user.html");
});



app.listen("3000", () => console.log("服务端启动"));

通过上面的代码我们可以看大,render方法的实现与我们前面在路由基本使用这一小节中的实现是一样的,都是根据传递过来的文件名,从view目录下面找到对应的文件,然后读取文件内容。最终该方法返回的是Promise对象。而不一样的就是在上面的代码中,我们不需要在写一个单独的方法来判断浏览器所请求的URL,而是直接使用koa-router路由中间件中的针对具体请求方式处理的方法来指明所请求的URL以及所要处理的具体内容。例如:

如果用户以get方式请求/list,那么就符合如下定义的路由规则,在其对应的处理函数中,调用了render方法来读取文件list.html中的内容。

当然在这里我们使用了asyncawait方式来处理异步。

router.get("/list", async (ctx) => {
  ctx.type = "html";
  ctx.body = await render("list.html");
});

4、路由前缀

关于什么是路由前缀以及路由前缀有什么作用,我们通过一个例子来看一下。

const Koa = require("Koa");
// 导入koa-router
const Router = require("koa-router");
const app = new Koa();
// 创建路由对象
const router = new Router();
app.use(router.routes());
router.get("/users/index", (ctx) => {
  ctx.body = "用户首页";
});

router.get("/users/list", (ctx) => {
  ctx.body = "用户列表页面";
});
router.get("/users/add", (ctx) => {
  ctx.body = "用户添加页面";
});
app.listen("3000", () => console.log("服务端启动"));

通过上面的代码,我们可以发现,如果输入的地址为/users/index, 返回的内容为"用户首页",如果输入的是/users/list 返回的内容为"用户列表页面"。

我们仔细观察一下上面代码中我们所定义的路由规则,就会发现每个路由规则中的地址都有/users, 如果我们在创建路由的时候,每次都输入/users就会变得比较麻烦。那么有没有解决办法呢?有,就是通过路由前缀来完成的。

下面我们把上面的代码,修改成如下的形式

const Koa = require("Koa");
// 导入koa-router
const Router = require("koa-router");

const app = new Koa();
// 创建路由对象
const router = new Router();
// 添加前缀
const usersRouter = new Router({ prefix: "/users" });
app.use(router.routes());
app.use(usersRouter.routes());

usersRouter.get("/index", (ctx) => {
  ctx.body = "用户首页";
});

usersRouter.get("/list", (ctx) => {
  ctx.body = "用户列表页面";
});
usersRouter.get("/add", (ctx) => {
  ctx.body = "用户添加页面";
});
// 下面所定义的路由规则没有使用/users前缀
router.get("/about", (ctx) => {
  ctx.body = "关于页面";
});
app.listen("3000", () => console.log("服务端启动"));

你仔细观察一下上面的代码,就会发现在上面的代码中,我们又创建了一个路由对象usersRouter.(如下代码所示):

const usersRouter = new Router({ prefix: "/users" });
app.use(usersRouter.routes());

在创建这个路由对象时,我们为其指定了一个参数{prefix: "/users"},表明的含义就是:接下来我们使用

usersRouter这个路由对象在创建路由规则的时候,每个地址都会自动带上/users这个前缀。

注意:prefix是固定的写法,表示路由前缀的意思。/users这个名称根据自己的情况来确定。

下面我们可以看到,我们首先使用usersRouter对象创建了如下的规则:

usersRouter.get("/index", (ctx) => {
  ctx.body = "用户首页";
});

通过上面这一小段代码,就可以看到get方法的第一个参数,在指定地址的时候,我们并没有像以前一样再手动指定/users这个前缀了。

虽然没有手动指定/users这个前缀,但是这里在创建usersRouter这个路由对象的时候已经指定了,所以当我们在浏览器的地址栏中输入如下地址时

http://localhost:3000/users/index

在浏览器中呈现出来的内容为"用户首页"。

同理,在创建如下两个路由规则的时候,也没有像以前一样再手动指定/users这个前缀了。

usersRouter.get("/list", (ctx) => {
  ctx.body = "用户列表页面";
});
usersRouter.get("/add", (ctx) => {
  ctx.body = "用户添加页面";
});

但是在浏览器的地址栏中分别输入如下两个地址时

http://localhost:3000/users/list
http://localhost:3000/users/add

浏览器中会分别展示出“用户列表页面”和“用户添加页面”。

下面,咱们就通过一张图来看一下具体的执行的过程:

动图
 

通过上图,我们可以看到最终的展示效果与我们前面分析的是一样的。

通过,对前面代码的学习,我们明白了在通过koa-router这个路由中间件创建路由规则时,对一些地址中的公共前缀可以在创建路由对象的时候就指定好。这样在创建具体的路由规则的时候,就不需要给每个地址都去添加相同的前缀了,这样就变得非常省事了。

当然,在前面我们所写的代码中,你可能也注意到了如下的一段代码,

router.get("/about", (ctx) => {
  ctx.body = "关于页面";
});

在上面这段代码中,我们使用的是router这个路由对象来创建路由规则,而没有使用usersRouter这个路由对象,所以创建的路由规则中的地址是没有/users这个前缀的。也就是说在浏览器的地址栏中,我们只需要输入如下地址:

http://localhost:3000/about

就可以在浏览器中查看到“关于页面”,这几个文字。

关于这块内容,你可以自己尝试一下。

5、路由基本拆分

通过前面几个小节的学习,现在我们已经掌握了koa-router 的基本使用了。但是,现在面临的一个问题是,我们把所有的路由规则都定义在一个 文件中了。那

么你可以想一下,随着代码增多,需要创建的路由规则也就越来越多,该文件会变得非常的臃肿,从而导致代码不利于阅读与维护。所以我们需要将这块内容进行

拆分,也就是说我们需要对路由内容进行拆分,将其拆分到不同的文件中。

具体 拆分的方式如下:

在当前项目中,创建api文件夹,在该文件夹中创建v1v2两个文件夹,表示创建的路由(API接口)的版本,因为随着项目需求的变更,会产生版本问题,所

以这里将对路由进行版本的划分(注:文件夹名字可以根据自己的情况进行命名)。v1 文件夹下存放的就是我们实现的第一个版本的路由,v2实现的就是根据项

目需求变更后的第二版本的路由。当然,你可以去创建v3,v4等文件夹,这就需要根据你的情况来确定了。

下面我们先创建第一个版本的路由规则。

v1目录下面创建两个文件分别是users.jsroles.js

通过users.jsroles.js这两个文件的名称,我们就可以看出,我们在定义路由规则的时候,可以将相关内容的路由规则定义到一个文件中。例如,关于 用户

信息管理的路由规则我们可以定义到users.js这个文件中,关于角色管理的路由规则,我们可以定义到roles.js这个文件中。这样,我们就实现了将路由规则

拆分到不同文件中 的目的,而且这样拆分完后,代码变得非常有条理,而且易于阅读。也就是说,我们看到v1/users.js文件,我们就知道在该文件下面定义的

是关于用户信息管理的路由规则,如果后期我们需要添加新的关于用户信息管理的路由规则,可以直接在该文件中进行添加。

下面,我们通过 一张图,看一下整体的目录结构。

现在我们已经将目录结构划分好了,下面看一下具体的代码实现。

我们先来看一下users.js文件中的代码,如下所示:

// 导入koa-router
const Router = require("koa-router");
// 创建路由对象,添加前缀
const usersRouter = new Router({ prefix: "/v1/users" });
usersRouter.get("/", (ctx, next) => {
  ctx.body = "用户列表";
});
usersRouter.get("/add", (ctx, next) => {
  ctx.body = "用户添加";
});
module.exports = usersRouter;

在上面的代码中,首先我们导入了koa-router这个路由中间件,然后在创建路由对象的时候,指定了路由的前缀为/v1/users.

接下来,创建了两个路由的规则,如果符合这两个路由规则,那么会给浏览器返回“用户列表”与“用户添加”这两项内容。

最后一定要记得将定义好的路由对象进行导出,如下所示

module.exports = usersRouter;

这样我们可以在其它的文件中去使用该路由。

关于roles.js文件中的代码实现基本上与users.js文件中的代码是一样的。

如下所示:

// 导入koa-router
const Router = require("koa-router");
// 创建路由对象,添加前缀
const rolesRouter = new Router({ prefix: "/v1/roles" });
rolesRouter.get("/", (ctx, next) => {
  ctx.body = "角色列表";
});
rolesRouter.get("/add", (ctx, next) => {
  ctx.body = "角色添加";
});
module.exports = rolesRouter;

在上面的代码中,首先我们也是导入了koa-router这个路由中间件,然后在创建路由对象的时候,指定了路由的前缀为/v1/roles.

接下来,创建了两个路由的规则,如果符合这两个路由规则,那么会给浏览器返回“角色列表”与“角色添加”这两项内容。

当然,最后也要将路由对象rolesRouter导出.

现在,我们已经创建好对应的路由规则了,那么应该怎样去使用呢?

这就需要我们修改一下app.js文件的代码,修改后的代码如下:

const Koa = require("koa");
const roles = require("./api/v1/roles");
const users = require("./api/v1/users");
const app = new Koa();
app.use(roles.routes());
app.use(users.routes());
app.listen("3000", () => console.log("服务端启动"));

通过上面的代码,我们可以看到app.js文件中的代码变得非常的简洁了。我们只需要导入roles.js文件与users.js文件中定义的路由,然后使用这些路由就可以了。

现在,你可以体会一下,根据上面对路由的拆分,整体结构是不是变得非常的清晰,而且代码变得简洁与易读了。

下面我们把程序启动一下,来看一下效果。

node app.js

我们可以通过以上命令来启动整个程序,对应效果如下图所示:

动图封面
 

通过上图,我们可以看到,在输入不同的URL地址后,展示出了不同的内容。在这里要注意的一点就是,在浏览器中输入地址的时候,对应的前缀不要漏掉,例如:/v1/users

关于路由基本拆分这块内容,在这我们就学完了,下面把这块内容做一个总结:

在最开始的时候我们将所有的路由规则都写到一个文件中,但是随着代码增多,需要创建的路由规则也就越来越多,该文件会变得非常的臃肿,从而导致代码不利

于阅读与维护,所以我们将路由拆分到不同的文件中。

具体的实现过程如下:

在当前项目中,创建api文件夹,在该文件夹中创建v1v2两个文件夹,表示创建的路由(API接口)的版本,因为随着项目需求的变更,会产生版本问题,所

以这里将对路由进行版本的划分(注:文件夹名字可以根据自己的情况进行命名)。v1 文件夹下存放的就是我们实现的第一个版本的路由,v2实现的就是根据项

目需求变更后的第二版本的路由。当然,你可以去创建v3,v4等文件夹,这就需要根据你的情况来确定了。我们先在v1文件夹下创建路由规则,在这我们将相关

内容的路由规则定义到一个文件中,例如:/v1/users.js文件,该文件中定义的是与用户管理相关的路由规则。要注意的是,一定要将定义好的路由进行导出。

同时,我们可以在app.js文件中将定义好的路由进行导入。

6、本课程总结

关于Koa2路由应用这节课的内容,我们已经学习完了,下面对这节课的内容来做了一个总结。

通过本节课的学习,我们首先知道了什么是路由 ,以及路由的作用。然后,我们实现了一个简单的路由规则,当然实现起来比较麻烦,并且代码不够美观,,为了解决这个问题我们使用了koa-router这个路由中间件来进行处理。

在学习koa-router这个中间件的时候,我们先学习了它的基本的安装与使用,然后又学习了怎样给路由去添加前缀,最后学习了关于路由的基本拆分。

关于路由应用这节课的内容是比较重要的,希望你认真学习。

 

前端高效学习路线:

怎么学习前端开发?求推荐学习路线?

编辑于 2022-12-27 11:53・IP 属地北京