Koa 安装与配置
1. 初始化项目
在终端中执行以下命令:
# 创建项目文件夹
mkdir koa
cd koa
# 初始化并安装依赖
npm init -y
npm install koa
npm install nodemon --save-dev
2. 修改 package.json
在 package.json
文件中进行如下修改:
{
"type": "module",
"scripts": {
"dev": "nodemon index.js",
"test": "echo \"Error: no test specified\" && exit 1"
}
}
3. 编写初始化代码
在终端中新建 index.js
文件:
# 测试代码文件
code index.js
在 index.js
中添加以下代码:
import Koa from 'koa';
const hostname = "127.0.0.1"; // 服务器监听的 IP 地址
const port = 8008; // 服务器监听的端口号
// 实例化一个 Koa 对象
const app = new Koa();
// 注册中间件
app.use(async ctx => {
ctx.body = "Helloworld"; // 设置响应体的内容
});
// 启动 HTTP 服务器
app.listen(port, hostname, () => {
console.log(`服务器已启动: http://${hostname}:${port}`);
});
4. 启动服务器
在终端中运行以下命令以启动服务器:
npm run dev
2. 中间件
import Koa from 'koa';
const hostname = "127.0.0.1"; // 服务器监听的 IP 地址
const port = 8008; // 服务器监听的端口号
// 实例化一个 Koa 对象
const app = new Koa();
// 演示中间件
app.use(async (ctx, next) => {
console.log(111);
await next();
console.log(222);
});
// 注册中间件
app.use(async ctx => {
ctx.body = "Helloworld"; // 设置响应体的内容
console.log(333);
});
// 启动 HTTP 服务器
app.listen(port, hostname, () => {
console.log(`服务器已启动: http://${hostname}:${port}`);
});
打印两遍是因为请求了图标,block即可
3. 安装和配置路由 - GET 请求
安装路由:
npm i @koa/router
测试代码:
import Koa from 'koa';
import Router from '@koa/router';
const hostname = "127.0.0.1"; // 服务器监听的 IP 地址
const port = 8008; // 服务器监听的端口号
// 实例化一个 Koa 对象
const app = new Koa();
const router = new Router(); // 实例化一个 Router 对象
router.get('/', async ctx => { // GET 请求
ctx.body = "Helloworld";
});
router.get('/test', async ctx => { // GET 请求
let id = ctx.query.id;
let web = ctx.query.web;
ctx.body = id + " : " + web;
});
router.get('/test2/id/:id/web/:web', async ctx => {
let id = ctx.params.id;
let web = ctx.params.web;
ctx.body = id + " : " + web;
});
router.redirect('/test3', 'https://www.baidu.com');
app.use(router.routes());
// ************************
const userRouter = new Router({ prefix: '/user' });
userRouter.get('/add', async ctx => {
ctx.body = "添加用户";
});
userRouter.get('/del', async ctx => {
ctx.body = "删除用户";
});
app.use(userRouter.routes());
// 在所有路由之后添加 404 处理函数
app.use(async ctx => {
if (!ctx.body) { // 若没有设置 ctx.body, 则说明没有匹配任何路由
ctx.status = 404;
ctx.body = '404 Not Found';
}
});
// 启动 HTTP 服务器
app.listen(port, hostname, () => {
console.log(`服务器已启动: http://${hostname}:${port}`);
});
4. POST 请求
安装 @koa/bodyparser
:
npm i @koa/bodyparser
测试代码:
import Koa from 'koa';
import Router from '@koa/router';
import BodyParser from '@koa/bodyparser';
const hostname = "127.0.0.1"; // 服务器监听的 IP 地址
const port = 8008; // 服务器监听的端口号
// 实例化一个 Koa 对象
const app = new Koa();
const router = new Router(); // 实例化一个 Router 对象
app.use(BodyParser()); // 使用 @koa/bodyparser 中间件来解析 POST 请求
// ------ POST 请求
// [application/x-www-form-urlencoded] http://127.0.0.1:8008/postUrl
router.post('/postUrl', async ctx => {
let id = ctx.request.body.id;
let web = ctx.request.body.web;
ctx.body = id + " : " + web;
});
// [application/json] http://127.0.0.1:8008/postJson
router.post('/postJson', async ctx => {
let id = ctx.request.body.id;
let web = ctx.request.body.web;
ctx.body = id + " : " + web;
});
app.use(router.routes()); // 将定义在 router 对象中的路由规则添加到 app 实例中
// 启动 HTTP 服务器
app.listen(port, hostname, () => {
console.log(`服务器已启动: http://${hostname}:${port}`);
});
5. 错误处理
测试代码:
import Koa from 'koa';
import Router from '@koa/router';
const hostname = "127.0.0.1";
const port = 8008;
const app = new Koa();
const router = new Router();
router.get('/', async ctx => {
throw new Error("测试");
});
/*
将 '错误处理中间件' 放在 '路由处理中间件' 之前, 当一个请求到达时,
会先经过 '错误处理中间件', 然后才会进入 '路由处理中间件',
是为了确保可以捕获错误
*/
app.use(async (ctx, next) => { // 错误处理中间件
try {
await next();
} catch (err) {
console.log('err:', err);
ctx.status = 500;
ctx.body = 'err: ' + err.message;
}
});
app.use(router.routes()); // 路由处理中间件
app.listen(port, hostname, () => {
console.log(`服务器已启动: http://${hostname}:${port}`);
});
6. 跨域
测试代码:
import Koa from 'koa';
import Router from '@koa/router';
import Cors from '@koa/cors';
const hostname = "127.0.0.1";
const port = 8008;
const app = new Koa();
const router = new Router(); // 实例化一个 Router 对象
app.use(Cors()); // 允许跨域请求
router.get('/', async ctx => { // GET 请求
ctx.body = "Helloworld";
});
app.use(router.routes()); // 将定义在 router 对象中的路由规则添加到 app 实例中
app.listen(port, hostname, () => {
console.log(`服务器已启动: http://${hostname}:${port}`);
});
7. Koa 图片上传功能实现指南
1. 安装依赖
在终端中执行以下命令以安装 @koa/multer
:
npm install @koa/multer
注意事项
安装过程中可能会出现如下警告:
npm warn deprecated @babel/plugin-proposal-export-namespace-from@7.18.9:
This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained.
Please use @babel/plugin-transform-export-namespace-from instead.
2. 编写代码
在 index.js
中添加以下代码:
import Koa from 'koa';
import Router from '@koa/router';
import BodyParser from '@koa/bodyparser';
import Cors from '@koa/cors';
import Multer from '@koa/multer';
import path from 'path';
const hostname = "127.0.0.1";
const port = 8008;
const app = new Koa();
const router = new Router(); // 实例化一个 Router 对象
app.use(BodyParser()); // 使用 @koa/bodyparser 中间件解析 POST 请求
app.use(Cors()); // 允许跨域请求
// 配置磁盘存储引擎
const storage = Multer.diskStorage({
destination: (request, file, callbackFunc) => { // 指定文件保存路径
callbackFunc(null, './upload');
},
filename: (request, file, callbackFunc) => { // 设置文件名
callbackFunc(null, Date.now() + path.extname(file.originalname));
},
});
const multer = Multer({ // 实例化一个 Multer 对象
storage, // 磁盘存储引擎
limits: { // 限制条件
fileSize: 2 * 1024 * 1024, // 限制文件大小为 2MB
},
fileFilter: (request, file, callbackFunc) => { // 文件过滤器
const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png'];
if (allowedTypes.includes(file.mimetype)) {
callbackFunc(null, true);
} else {
callbackFunc(new Error('不支持的文件类型'), false);
}
}
});
// 上传接口
router.post('/upload', multer.single('file'), async ctx => {
const file = ctx.request.file; // 获取上传的文件信息
if (file) {
console.log(file);
ctx.body = "文件上传成功";
}
});
// 错误处理中间件
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
ctx.status = 500;
ctx.body = 'err: ' + err.message;
}
});
app.use(router.routes()); // 路由处理中间件
// 启动服务器
app.listen(port, hostname, () => {
console.log(`服务器已启动: http://${hostname}:${port}`);
});
3. 启动服务器
在终端中运行以下命令以启动服务器:
npm run dev
4. 上传文件
使用 POST 请求上传文件到 http://127.0.0.1:8008/upload,确保请求中包含名为 file
的文件字段。
8. Cookie
测试代码:
import Koa from 'koa';
import Router from '@koa/router';
const hostname = "127.0.0.1";
const port = 8008;
const app = new Koa();
const router = new Router(); // 实例化一个 Router 对象
// Cookie 可用于在浏览器中存储数据
router.get('/', async ctx => {
// 赋值
ctx.cookies.set("name", encodeURIComponent("hello")); // encodeURIComponent: URL 编码
ctx.cookies.set("web", "baidu.com", {
maxAge: 5 * 1000, // 30 秒 [maxAge: 有效期 单位: 毫秒]
httpOnly: false // 允许浏览器通过 JS 访问和修改该 cookie
});
// 取值 - 在同一个请求内, 无法立即获取到刚刚设置的 cookie 的值
let name = ctx.cookies.get("name");
console.log("name:", decodeURIComponent(name)); // decodeURIComponent: URL 解码
// 删除
// ctx.cookies.set("name", "", { maxAge: 0 });
ctx.body = "Helloworld";
});
app.use(router.routes()); // 将定义在 router 对象中的路由规则添加到 app 实例中
app.listen(port, hostname, () => {
console.log(`服务器已启动: http://${hostname}:${port}`);
});
9. Session(存在客户端的 Cookie 中,一般别用)
安装 koa-session
:
npm i koa-session
测试代码:
import Koa from 'koa';
import Router from '@koa/router';
import Session from 'koa-session';
const hostname = "127.0.0.1";
const port = 8008;
const app = new Koa();
const router = new Router(); // 实例化一个 Router 对象
// koa-session 默认将 session 数据存储在客户端的 cookie 中
app.keys = ['session.dengruicode.com']; // 设置会话签名的密钥
const CONFIG = {
key: 'DR', // 存储在 cookie 中的键名
maxAge: 24 * 60 * 60 * 1000, // 24 小时 有效期 (单位: 毫秒)
signed: true, // 是否启用会话签名, 用于防止 CSRF 攻击
secure: false, // 是否仅通过 https 协议发送 cookie
};
app.use(Session(CONFIG, app));
router.get('/', async ctx => {
// 赋值
ctx.session.name = "邓瑞";
ctx.session.url = "dengruicode.com";
if (!ctx.session.user) {
ctx.session.user = 100;
} else {
ctx.session.user++;
}
// 取值
let name = ctx.session.name;
console.log("name:", name);
// 删除
// ctx.session = null; // 清空
// delete ctx.session.name; // 删除 session 中的 name 属性
ctx.body = "用户:" + ctx.session.user;
});
app.use(router.routes()); // 将定义在 router 对象中的路由规则添加到 app 实例中
app.listen(port, hostname, () => {
console.log(`服务器已启动: http://${hostname}:${port}`);
});
10. JWT
安装 jsonwebtoken
:
npm i jsonwebtoken
JWT 结构
JWT(JSON Web Token)是一种基于令牌的认证和授权机制,由三部分组成:Header(头部)、Payload(负载)、Signature(签名)。
Header(头部)
{
"alg": "HS256", // algorithm 算法
"typ": "JWT" // type 类型
}
Payload(负载)
{
"sub": 1, // Subject 主题 (用户唯一 ID)
"iss": "dengruicode.com", // Issuer 发行者
"iat": 1719930255, // Issued At 发行时间
"nbf": 1719930255, // Not Before 生效时间
"exp": 1720016655, // Expiration Time 过期时间
"aud": [ // Audience 观众字段为空, 表示没有观众限制, 可以被任何接收方处理
""
],
"data": { // 自定义数据
"name": "邓瑞",
"gender": "男"
}
}
Signature(签名)
HMACSHA256(
base64UrlEncode(Header) + "." +
base64UrlEncode(Payload),
密钥
)
测试代码:
import Koa from 'koa';
import Router from '@koa/router';
import JWT from 'jsonwebtoken';
const hostname = "127.0.0.1";
const port = 8008;
const app = new Koa();
const router = new Router(); // 实例化一个 Router 对象
router.get('/', async ctx => {
let key = 'koaTest'; // 密钥
let token = generateToken(key); // 生成 token
parseToken(token, key); // 解析 token
ctx.body = token;
});
app.use(router.routes()); // 将定义在 router 对象中的路由规则添加到 app 实例中
// 生成 token
let generateToken = key => {
let id = 1; // 用户唯一 ID
let now = Math.floor(Date.now() / 1000); // 当前时间戳 单位: 秒
let expire = 24 * 60 * 60;
// 负载
let payload = {
sub: id, // Subject 主题 (用户唯一 ID)
iss: 'dengruicode.com', // Issuer 发行者
iat: now, // Issued At 发行时间
nbf: now, // Not Before 生效时间
exp: now + expire, // Expiration Time 过期时间
aud: [''], // Audience 观众字段为空, 表示没有观众限制, 可以被任何接收方处理
data: { // 自定义数据
name: '邓瑞',
gender: '男',
}
};
// 使用负载(payload)、密钥(key)和指定的签名算法(HS256)生成 token
let token = JWT.sign(payload, key, { algorithm: 'HS256' });
return token;
};
// 解析 token
let parseToken = (token, key) => {
let payload = JWT.verify(token, key, { algorithm: 'HS256' });
console.log('解析后的 payload:', payload);
};
app.listen(port, hostname, () => {
console.log(`服务器已启动: http://${hostname}:${port}`);
});
以上是 Koa 的基本使用指南和功能实现,包括中间件、路由、错误处理、跨域、文件上传、Cookie、Session 和 JWT 等功能。确保在实际开发中根据需求进行适当的修改和扩展。