第十节: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 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 
posted @   Yaopengfei  阅读(1058)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2020-02-16 第三节:Vuejs常用特性2和图书案例
点击右上角即可分享
微信分享提示