Koa2框架路由应用,Koa2前景、Koa2中间件
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
中的内容。
当然在这里我们使用了async
与await
方式来处理异步。
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
文件夹,在该文件夹中创建v1
和v2
两个文件夹,表示创建的路由(API
接口)的版本,因为随着项目需求的变更,会产生版本问题,所
以这里将对路由进行版本的划分(注:文件夹名字可以根据自己的情况进行命名)。v1
文件夹下存放的就是我们实现的第一个版本的路由,v2
实现的就是根据项
目需求变更后的第二版本的路由。当然,你可以去创建v3
,v4
等文件夹,这就需要根据你的情况来确定了。
下面我们先创建第一个版本的路由规则。
在v1
目录下面创建两个文件分别是users.js
和roles.js
。
通过users.js
和roles.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
文件夹,在该文件夹中创建v1
和v2
两个文件夹,表示创建的路由(API
接口)的版本,因为随着项目需求的变更,会产生版本问题,所
以这里将对路由进行版本的划分(注:文件夹名字可以根据自己的情况进行命名)。v1
文件夹下存放的就是我们实现的第一个版本的路由,v2
实现的就是根据项
目需求变更后的第二版本的路由。当然,你可以去创建v3
,v4
等文件夹,这就需要根据你的情况来确定了。我们先在v1
文件夹下创建路由规则,在这我们将相关
内容的路由规则定义到一个文件中,例如:/v1/users.js
文件,该文件中定义的是与用户管理相关的路由规则。要注意的是,一定要将定义好的路由进行导出。
同时,我们可以在app.js
文件中将定义好的路由进行导入。
6、本课程总结
关于Koa2
路由应用这节课的内容,我们已经学习完了,下面对这节课的内容来做了一个总结。
通过本节课的学习,我们首先知道了什么是路由 ,以及路由的作用。然后,我们实现了一个简单的路由规则,当然实现起来比较麻烦,并且代码不够美观,,为了解决这个问题我们使用了koa-router
这个路由中间件来进行处理。
在学习koa-router
这个中间件的时候,我们先学习了它的基本的安装与使用,然后又学习了怎样给路由去添加前缀,最后学习了关于路由的基本拆分。
关于路由应用这节课的内容是比较重要的,希望你认真学习。
前端高效学习路线: