第十节:Koa框架详解(基本使用、路由、参数解析、响应结果、文件上传、静态资源、异常处理)
一. 基本使用
1. 简介
koa:node.js的下一代web框架; 事实上,koa是express同一个团队开发的一个新的Web框架:
(1). 目前团队的核心开发者TJ的主要精力也在维护Koa,express已经交给团队维护了;
(2). Koa旨在为Web应用程序和API提供更小、更丰富和更强大的能力;
(3). 相对于express具有更强的异步处理能力;
(4). Koa的核心代码只有1600+行,是一个更加轻量级的框架;
(5). 我们可以根据需要安装和使用中间件;
2. 基本使用
导入 → 实例化 → 监听 → app.use 或者 路由中间件处理各种请求
【npm install koa】
const Koa = require("koa");
const app = new Koa();
app.listen(9090, () => {
console.log("---------------koa服务器启动成功,端口9090----------------");
});
// 1. 基本使用
{
app.use((ctx, next) => {
ctx.body = "请求成功了";
});
}
3. 参数分析
(1). ctx:上下文(Context)对象;
koa并没有像express一样,将req和res分开,而是将它们作为ctx的属性;
ctx代表一次请求的上下文对象;
ctx.request:获取请求对象【Koa封装的请求对象】; 另外还可以 ctx.req 【node封装的对象】
ctx.response:获取响应对象【Koa封装的请求对象】; 另外还可以 ctx.res 【node封装的对象】
(2). next:本质上是一个dispatch,类似于express之前的next;
{
app.use((ctx, next) => {
console.log("first middleware~");
// 1.请求对象
console.log(ctx.request); // 请求对象: Koa封装的请求对象
console.log(ctx.req); // 请求对象: Node封装的请求对象
// 2.响应对象
console.log(ctx.response); // 响应对象: Koa封装的响应对象
console.log(ctx.res); // 响应对象: Node封装的响应对象
// 3.其他属性
console.log(ctx.query);
console.log(ctx.params);
// 4. 向下传递
next();
});
app.use((ctx, next) => {
console.log("second middleware~");
ctx.body = "请求成功了";
});
}
4. 区分请求路径和方法
在koa中,并不能像express那样,app.use 或 app.post, 只有通过if判断 ctx.path、ctx.method,相当繁琐。
所以推荐使用路由机制。
{
app.use((ctx, next) => {
if (ctx.path === "/users") {
if (ctx.method === "GET") {
ctx.body = "/users GET";
} else if (ctx.method === "POST") {
ctx.body = "/users POST";
}
} else {
ctx.body = "请求成功了";
}
});
}
二. 路由
1. 说明
koa官方并没有给我们提供路由的库,我们可以选择第三方库:koa-router
2. 使用
(1). 通过指令 【npm install @koa/router】 进行安装
(2). 引入路由
(3). 创建路由对象, prefix: "/users" 前缀,表示后面注册的所有请求路径都会加上这个前缀
(4). 注册各种路由中间件,区分请求方式和路径 (可以直接使用 get、post、put等方法)
(5). 让路由中间件生效 app.use(userRouter.routes());
const Koa = require("koa");
const app = new Koa();
app.listen(9090, () => {
console.log("---------------koa服务器启动成功,端口9090----------------");
});
// 1. 路由的使用
{
// 1.1 引入路由
const koaRouter = require("@koa/router");
// 1.2 创建路由对象
const userRouter = new koaRouter({ prefix: "/users" }); //后面所有的地址都会拼上 /users这个前缀
// 1.3 注册各种中间件,区分请求方式和路径
userRouter.get("/", (ctx, next) => {
ctx.body = "users list data~";
});
userRouter.get("/:id", (ctx, next) => {
const id = ctx.params.id;
ctx.body = "获取某一个用户" + id;
});
userRouter.post("/", (ctx, next) => {
ctx.body = "创建用户成功~";
});
userRouter.delete("/:id", (ctx, next) => {
const id = ctx.params.id;
ctx.body = "删除某一个用户" + id;
});
userRouter.patch("/:id", (ctx, next) => {
const id = ctx.params.id;
ctx.body = "修改某一个用户" + id;
});
// 1.4 让路由中间件生效
app.use(userRouter.routes());
app.use(userRouter.allowedMethods()); //加上这句话,当发送的请求方式没有定义的话,会提示method not found
}
3. 补充 allowedMethods 的作用?
用于判断某一个method是否支持
(1). 如果我们请求 get,那么是正常的请求,因为我们有实现get;
(2). 如果我们请求 put、delete、patch,那么就自动报错:Method Not Allowed,状态码:405;
(3). 如果我们请求 link、copy、lock,那么久自动报错:NotImplemented,状态码:501;
4. 单独抽离到一个文件中
详见下面代码
{
const userRouter = require("./router/myRouter");
app.use(userRouter.routes());
app.use(userRouter.allowedMethods()); //加上这句话,当发送的请求方式没有定义的话,会提示method not found
}
单独抽离一个文件:
查看代码
// 1 引入路由
const koaRouter = require("@koa/router");
// 2 创建路由对象
const userRouter = new koaRouter({ prefix: "/users" }); //后面所有的地址都会拼上 /users这个前缀
// 3 注册各种中间件,区分请求方式和路径
userRouter.get("/", (ctx, next) => {
ctx.body = "users list data~";
});
userRouter.get("/:id", (ctx, next) => {
const id = ctx.params.id;
ctx.body = "获取某一个用户" + id;
});
userRouter.post("/", (ctx, next) => {
ctx.body = "创建用户成功~";
});
userRouter.delete("/:id", (ctx, next) => {
const id = ctx.params.id;
ctx.body = "删除某一个用户" + id;
});
userRouter.patch("/:id", (ctx, next) => {
const id = ctx.params.id;
ctx.body = "修改某一个用户" + id;
});
module.exports = userRouter;
三. 参数解析
1. 通过post请求发送json格式
【对应postman中的 raw--json】
(1). 需要通过指令安装 【npm install koa-bodyparser】
(2). 引入并使用解析中间件
const bodyParser = require("koa-bodyparser");
app.use(bodyParser());
(3). 通过 ctx.request.body 获取json数据
特别注意:如果使用router中间件,中间件的注册必须放到解析中间件的后面
const Koa = require("koa");
const app = new Koa();
app.listen(9090, () => {
console.log("---------------koa服务器启动成功,端口9090----------------");
});
//路由
const koaRouter = require("@koa/router");
const router = new koaRouter({ prefix: "/users" }); //后面所有的地址都会拼上 /users这个前缀
// 1. 通过post请求发送json格式
{
// 引入并使用解析中间件
const bodyParser = require("koa-bodyparser");
app.use(bodyParser());
// 注册中间件
router.post("/addUser", (ctx, next) => {
// 获取请求数据
console.log(ctx.request.body); //{ userAccount: 'admin', userPwd: '123456' }
console.log(ctx.req.body); // undefined
ctx.body = "请求成功";
});
}
// 路由中间件的使用需要放到上述解析中间件的后面
app.use(router.routes());
app.use(router.allowedMethods()); //加上这句话,当发送的请求方式没有定义的话,会提示method not found
2. 通过post请求发送x-www-form-urlencoded格式
【对应postman中的x-www-form-urlencoded】
完全同上
{
// 引入并使用解析中间件
const bodyParser = require("koa-bodyparser");
app.use(bodyParser());
// 注册中间件
router.post("/addUser", (ctx, next) => {
// 获取请求数据
console.log(ctx.request.body); //{ userAccount: 'admin', userPwd: '123456' }
console.log(ctx.req.body); // undefined
ctx.body = "请求成功";
});
}
3. 通过post请求发送form-data格式
【对应postman中的form-data】
(1). 通过使用multer中间件,需要先【npm install @koa/multer】
(2). 然后导入并使用中间件,就可以接受到客户端传递过来的form-data中的数据了。
{
// 引入并使用解析中间件
const multer = require("@koa/multer");
const formParser = multer();
// 注册中间件
router.post("/addUser", formParser.any(), (ctx, next) => {
// 获取请求数据
console.log(ctx.request.body); //{ userAccount: 'admin', userPwd: '123456' }
console.log(ctx.req.body); // undefined
ctx.body = "请求成功";
});
}
4. 通过get请求中的URL的query
形如:http://localhost:9090/users?userAccount=admin&userPwd=123456
在node中通过 ctx.query 直接就可以获取这个对象
{
router.get("/", (ctx, next) => {
console.log(ctx.query); //{ userAccount: 'admin', userPwd: '123456' }
ctx.body = "请求成功" + JSON.stringify(ctx.query);
});
}
5. 通过get请求中的URL的params
形如:http://localhost:9090/users/admin/123456
在node中的匹配路径为:"/users/:userAccount/:userPwd",最终通过ctx.params获取
{
router.get("/:userAccount/:userPwd", (ctx, next) => {
console.log(ctx.params); //{ userAccount: 'admin', userPwd: '123456' }
ctx.body = "请求成功" + JSON.stringify(ctx.params);
});
}
四. 响应结果
1. 响应方式
ctx.status 设置状态码
ctx.body 设置返回内容
注意:如果 ctx.status尚未设置,Koa会自动将状态设置为200或204
2. 数据类型
string :字符串数据
Buffer :Buffer数据
Stream :流数据
Object|| Array:对象或者数组
null :不输出任何内容
const Koa = require("koa");
const app = new Koa();
app.listen(9090, () => {
console.log("---------------koa服务器启动成功,端口9090----------------");
});
//路由
const koaRouter = require("@koa/router");
const router = new koaRouter();
router.post("/checkLogin", (ctx, next) => {
// 1.body的类型是string
// ctx.body = 'user list data~'
// 2.body的类型是Buffer
// ctx.body = Buffer.from('你好啊, ypf~')
// 3.body的类型是Stream
// const readStream = fs.createReadStream("./uploads/111.jpg");
// ctx.type = "image/jpeg";
// ctx.body = readStream;
// 4.body的类型是数据(array/object) => 使用最多
ctx.status = 201;
ctx.body = {
status: "ok",
msg: "登录成功",
data: [
{ id: 111, name: "iphone", price: 100 },
{ id: 112, name: "xiaomi", price: 990 },
],
};
// 5.body的值是null, 自动设置http status code为204
// ctx.body = null
});
// 路由中间件的注册需要放到上述其它中间件的后面
app.use(router.routes());
app.use(router.allowedMethods()); //加上这句话,当发送的请求方式没有定义的话,会提示method not found
五. 文件上传
1. 说明
(1). 需要通过指令安装中间件 【npm install @koa/multer】
(2). 在multer中可以配置文件存放路径 和 文件命名规则
2. 单文件上传
通过 myUpload.single("myFile1")方法来配置,这里的myFile1为参数名
代码分享:
const Koa = require("koa");
const app = new Koa();
app.listen(9090, () => {
console.log("---------------koa服务器启动成功,端口9090----------------");
});
//路由
const koaRouter = require("@koa/router");
const router = new koaRouter();
// 文件上传中间件
const multer = require("@koa/multer");
// 1. 单文件上传
{
let myUpload = multer({
storage: multer.diskStorage({
// 文件存放路径
destination(req, file, callback) {
callback(null, "./uploads");
},
// 文件命名规则
filename(req, file, callback) {
// 时间戳_文件名.后缀名 (file.originalname: 文件名.后缀名)
callback(null, Date.now() + "_" + file.originalname);
},
}),
});
router.post("/singleUpload", myUpload.single("myFile1"), (ctx, next) => {
console.log(ctx.request.file);
ctx.body = "文件上传成功~";
});
}
3. 多文件上传
通过 myUpload.array("myManyFile1")方法来配置,这里的myManyFile1为参数名
代码分享:
{
let myUpload = multer({
// dest: "./uploads", //这种写法没有后缀名
storage: multer.diskStorage({
destination(req, file, callback) {
callback(null, "./uploads");
},
filename(req, file, callback) {
// 时间戳_文件名.后缀名 (file.originalname: 文件名.后缀名)
callback(null, Date.now() + "_" + file.originalname);
},
}),
});
router.post("/manyUpload", myUpload.array("myManyFile1"), (ctx, next) => {
console.log(ctx.request.files);
ctx.body = "文件上传成功~";
});
}
六. 静态资源
需要通过指令安装 【npm install koa-static】
然后引入: const static = require("koa-static");
然后注册使用:app.use(static("./uploads"));
如下案例,访问 http://localhost:9090/ 可以打开静态网站
访问 http://localhost:9090/111.jpg 可以打开图片
const Koa = require("koa");
const app = new Koa();
app.listen(9090, () => {
console.log("---------------koa服务器启动成功,端口9090----------------");
});
// 引入静态资源中间件
const static = require("koa-static");
// 部署静态资源
app.use(static("./uploads"));
app.use(static("./build"));
七. 异常处理
通过 ctx.app.emit(eventName,...args), 第一个参数为监听器的名称,后续参数个数自定义
然后使用 app.on("eventName", (errCode, ctx) => {}) ,回调函数中的参数,均为emit中传递过来的
代码分享:
const Koa = require("koa");
const app = new Koa();
app.listen(9090, () => {
console.log("---------------koa服务器启动成功,端口9090----------------");
});
//路由
const koaRouter = require("@koa/router");
const router = new koaRouter();
// 引入并使用解析中间件
const bodyParser = require("koa-bodyparser");
app.use(bodyParser());
// 路由中间件的注册需要放到上述其它中间件的后面
app.use(router.routes());
app.use(router.allowedMethods()); //加上这句话,当发送的请求方式没有定义的话,会提示method not found
router.post("/checkLogin", (ctx, next) => {
let { userAccount, userPwd } = ctx.request.body;
if (!userAccount || !userPwd) {
// 实际上是一个EventEmitter
ctx.app.emit("ErrorHandle", "error1", ctx);
} else if (userAccount !== "admin" || userPwd !== "123456") {
ctx.app.emit("ErrorHandle", "error2", ctx);
} else {
ctx.body = { status: "ok", msg: "登录成功" };
}
});
// 统一处理异常中间件(可以单独抽离一个文件 eg:error-handle.js)
//回调中的两个参数 errCode, ctx,均为上述emit中传递过来的
app.on("ErrorHandle", (errCode, ctx) => {
let msg = "";
switch (errCode) {
case "error1":
msg = "用户名或密码为空";
break;
case "error2":
msg = "用户名或密码不正确";
break;
default:
msg = "登录失败";
break;
}
ctx.body = { status: "error", msg };
});
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2020-02-16 第三节:Vuejs常用特性2和图书案例