阅读视图

发现新文章,点击刷新页面。

Koa.js 教程 | 一份不可多得的 Node.js 的 Web 框架 Koa.js 教程

第一章 安装和配置 koa

Koa 是一个轻量级、现代化的框架, 由 Express 原班人马开发

初始化配置文件 package.json

npm init -y

配置 package.json (ESM规范)

{
     "type": "module",
     "name": "demo",
     "version": "1.0.0",
     "main": "index.js",
     "scripts": {
          "dev":"nodemon index.js",
           "test": "echo \"Error: no test specified\" && exit 1"
     },
     "keywords": [],
     "author": "",
     "license": "ISC",
     "description": ""
}

npm 官网

     www.npmjs.com

安装koa      

npm i koa

     全局安装 nodemon

  .  npm i nodemon -g

     当 nodemon 检测到监视的文件发生更改时, 会自动重新启动应用

第二章 创建并启动 http 服务器

中间件

中间件是处理 HTTP 请求和响应的函数,它们可以做以下操作:

  • 处理请求(例如解析请求体、验证用户身份等)
  • 修改响应(例如设置响应头、发送响应体等)
  • 执行后续中间件

中间件 - 很重要的概念 !!!!!!!

注意 : app.use() 方法用于注册 中间件

中间件 是处理 http 请求和响应的函数 , 当一个请求到达服务器时, 会从第一个中间件开始执行, 直到最后一个中间件

上下文对象 ctx

在 Koa 中,ctx(上下文)对象是每个中间件函数的核心,它包含了请求和响应的所有信息。所有的 HTTP 请求和响应都通过 ctx 进行处理。

上下文对象 ctx ( context ) 包含了与当前 http 请求相关的所有信息

如: http方法、url、请求头、请求体、查询参数等

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 = "juejin.cn" // 使用 ctx.body 设置响应体的内容
})

//启动 http 服务器, 并在指定的ip地址(127.0.0.1)和端口(8008)上监听连接请求
app.listen(port, hostname, () => {
    console.log(`服务器已启动: http://${hostname}:${port}`)
})

第三章 洋葱模型

洋葱模型

当你处理一个请求时,

可以想象成是在 "剥洋葱" ,从外向内一层一层地往里剥,直到剥到中心部分

这个过程涉及对 请求 的多个层面进行解析、验证、处理

在处理完洋葱(请求)后,

构建 响应 的过程就像是从精心准备的食材 ( 处理请求 后得到的数据) 开始,

从内向外逐层添加调料(格式化、封装等),最终形成一道色香味俱佳的菜肴(响应)

image.png

import Koa from 'koa'

const hostname = "127.0.0.1" //服务器监听的ip地址
const port = 8008 //服务器监听的端口号

/*
    实例化一个 Koa 对象
    实例化是指根据一个类创建具体对象的过程
*/
const app = new Koa()

/*
    app.use() 方法用于注册中间件
    中间件是处理 http 请求和响应的函数
    当一个请求到达服务器时, 会从第一个中间件开始执行, 直到最后一个中间件
    
    上下文对象 ctx(context) 包含了与当前 http 请求相关的所有信息
    如: http方法、url、请求头、请求体、查询参数等
*/
app.use(async (ctx,next) => {
    console.log(1)
    await next() //若中间件调用了next(),会暂停当前中间件的执行,将控制权传递给下一个中间件
    console.log(2)
})

app.use(async (ctx,next) => { 
    console.log(3)
    await next()
    console.log(4)
})

//当中间件没有再调用next(),则不需要再将控制权传递给下一个中间件,控制权会按照相反的顺序执行
app.use(async (ctx,next) => {
    console.log(5)
    ctx.body = "dengruicode.com" // 使用 ctx.body 设置响应体的内容
})

//启动 http 服务器, 并在指定的ip地址(127.0.0.1)和端口(8008)上监听连接请求
app.listen(port, hostname, () => {
    console.log(`服务器已启动: http://${hostname}:${port}`)
})

第四章 安装和配置路由 - get请求

在 Koa 中,koa-router 是一个轻量级的路由中间件,它可以帮助你定义路由、处理 HTTP 请求并解析请求参数。通过使用 koa-router,你可以创建一个灵活的路由系统,轻松地组织和管理 Koa 应用的各个部分。

安装 koa-router

首先,你需要安装 koa-router

npm install @koa/router       # 注意:新版 koa-router 包名是 @koa/router
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请求
//路由是根据客户端发送的请求(包括请求的路径、方法等)调用与之匹配的处理函数
//根路由 http://127.0.0.1:8008/
router.get('/', async ctx => { //get请求
    ctx.body = "dengruicode.com"
})

//查询参数 http://127.0.0.1:8008/test?id=001&web=dengruicode.com
router.get('/test', async ctx => { //get请求
    let id = ctx.query.id
    let web = ctx.query.web
    ctx.body = id + " : " + web
})

//路径参数 http://127.0.0.1:8008/test2/id/002/web/www.dengruicode.com
router.get('/test2/id/:id/web/:web', async ctx => {
    let id = ctx.params.id
    let web = ctx.params.web
    ctx.body = id + " : " + web
})

//重定向路由 http://127.0.0.1:8008/test3
router.redirect('/test3', 'https://www.baidu.com')

app.use(router.routes()) //将定义在 router 对象中的路由规则添加到 app 实例中

//------ 路由分组
//http://127.0.0.1:8008/user/add
//http://127.0.0.1:8008/user/del

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'
    }
})

app.listen(port, hostname, () => {
    console.log(`服务器已启动: http://${hostname}:${port}`)
})

第五章 post请求

安装 koa-body

Koa 原生不支持解析 POST 请求体,需安装 koa-body 中间件:

npm install koa-body

POST 请求处理示例

修改 src/index.js,新增 POST 路由:

import Koa from 'koa';
import Router from '@koa/router';
import { koaBody } from 'koa-body';

const app = new Koa();
const router = new Router();
const port = 8008;

// 注册 koa-body 中间件:解析 JSON、表单、文件类型的 POST 数据
app.use(koaBody({
  multipart: true, // 支持文件上传(后续第八章用)
  json: true, // 解析 JSON 格式
  urlencoded: true // 解析表单格式(application/x-www-form-urlencoded)
}));

// 1. 处理 JSON 格式 POST 请求
router.post('/api/json', async (ctx) => {
  const { name, age } = ctx.request.body;
  ctx.body = {       // ctx.request.body 是 koa-body 解析后的 POST 数据
    code: 200,
    msg: "JSON 数据接收成功",
    data: { name, age }
  };
});

// 2. 处理表单格式 POST 请求
router.post('/api/form', async (ctx) => {
  const { username, password } = ctx.request.body;
  ctx.body = {
    code: 200,
    msg: "表单数据接收成功",
    data: { username, password }
  };
});

app.use(router.routes());

// 404 处理
app.use(async (ctx) => {
  ctx.status = 404;
  ctx.body = '404 Not Found';
});

app.listen(port, () => {
  console.log(`POST 服务器启动:http://localhost:${port}`);
});

测试 POST 请求(两种方式)

方式 1:Postman 测试

  • 请求地址:http://localhost:8008/api/json

  • 请求方法:POST

  • 请求体:选择 raw > JSON,输入:

    { "name": "张三", "age": 20 }
    
  • 响应:{"code":200,"msg":"JSON 数据接收成功","data":{"name":"张三","age":20}}

方式 2:curl 命令测试

# 测试 JSON 格式
curl -X POST -H "Content-Type: application/json" -d '{"name":"张三","age":20}' http://localhost:8008/api/json

# 测试表单格式
curl -X POST -d "username=admin&password=123456" http://localhost:8008/api/form

第六章 错误处理

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()

//http://127.0.0.1:8008/
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}`)
})

第七章 允许跨域请求

安装跨域中间件

npm install @koa/cors

跨域配置示例

import Koa from 'koa';
import Router from '@koa/router';
import Cors from '@koa/cors';

const app = new Koa();
const router = new Router();
const port = 8008;

app.use(Cors()) //允许跨域请求

// 测试跨域路由
router.get('/api/cors', async (ctx) => {
  ctx.body = {
    code: 200,
    msg: "跨域请求成功"
  };
});

app.use(router.routes());

app.listen(port, () => {
  console.log(`跨域服务器启动:http://localhost:${port}`);
});

测试跨域

在任意前端项目(如 Vue / React / HTML 文件)中发送请求:

// 前端代码示例
fetch('http://localhost:8008/api/cors')
  .then(res => res.json())
  .then(data => console.log(data)) // 输出 {code:200, msg:"跨域请求成功"}
  .catch(err => console.error(err));

无跨域报错即配置成功。

第八章 上传图片

依赖准备(复用 koa-body)

koa-body 已支持文件上传,无需额外安装依赖,只需确保配置 multipart: true

图片上传示例

import Koa from 'koa';
import Router from '@koa/router';
import { koaBody } from 'koa-body';
import fs from 'fs';
import path from 'path';

const app = new Koa();
const router = new Router();
const port = 8008;

// 1. 创建上传目录(不存在则创建)
const uploadDir = path.join(__dirname, 'uploads');
if (!fs.existsSync(uploadDir)) {
  fs.mkdirSync(uploadDir, { recursive: true });
}

// 2. 配置 koa-body 支持文件上传
app.use(koaBody({
  multipart: true, // 开启文件上传
  formidable: {
    uploadDir: uploadDir, // 临时存储目录
    keepExtensions: true, // 保留文件扩展名(如 .png/.jpg)
    maxFieldsSize: 2 * 1024 * 1024, // 限制文件大小 2MB
    filename: (name, ext, part, form) => {
      // 自定义文件名:时间戳 + 原扩展名,避免重复
      return Date.now() + ext;
    }
  }
}));

// 3. 图片上传接口
router.post('/api/upload', async (ctx) => {
  // ctx.request.files 是上传的文件对象
  const file = ctx.request.files.file; // 前端上传的文件字段名需为 file
  if (!file) {
    ctx.status = 400;
    ctx.body = { code: 400, msg: "请选择上传的图片" };
    return;
  }

  // 返回文件信息
  ctx.body = {
    code: 200,
    msg: "图片上传成功",
    data: {
      filename: file.newFilename, // 自定义后的文件名
      path: `/uploads/${file.newFilename}`, // 访问路径
      size: file.size // 文件大小(字节)
    }
  };
});

// 4. 静态文件访问:让上传的图片可通过 URL 访问
app.use(async (ctx, next) => {
  if (ctx.path.startsWith('/uploads/')) {
    const filePath = path.join(uploadDir, ctx.path.replace('/uploads/', ''));
    if (fs.existsSync(filePath)) {
      ctx.type = path.extname(filePath).slice(1); // 设置响应类型(如 png/jpg)
      ctx.body = fs.createReadStream(filePath); // 读取文件并返回
      return;
    }
    ctx.status = 404;
    ctx.body = "文件不存在";
    return;
  }
  await next();
});

app.use(router.routes());

app.listen(port, () => {
  console.log(`图片上传服务器启动:http://localhost:${port}`);
});

测试图片上传

方式 1:Postman 测试

  • 请求地址:http://localhost:8008/api/upload
  • 请求方法:POST
  • 请求体:选择 form-data,Key 为 file,Type 选 File,上传一张图片。
  • 响应:返回文件路径,如 http://localhost:8008/uploads/1738987654321.png,访问该 URL 可查看图片。

方式 2:curl 命令测试

终端输入 bash 命令

curl -X POST -F "file=@/你的图片路径/xxx.png" http://localhost:8008/api/upload

第九章 cookie

Cookie 是存储在客户端浏览器的小型文本数据,Koa 内置 ctx.cookies API 可以操作 Cookie。

Cookie 操作示例

import Koa from 'koa'
import Router from '@koa/router'
 
const app = new Koa();
const router = new Router();
const port = 8008;

// 1. 设置 Cookie
router.get('/cookie/set', async (ctx) => {
  // ctx.cookies.set(名称, 值, 配置)
  ctx.cookies.set(
    'username', 
    encodeURIComponent('张三'), 
    {
      maxAge: 24 * 60 * 60 * 1000, // 过期时间 1 天(毫秒)
      httpOnly: true, // 仅允许服务端访问,防止 XSS 攻击
      secure: false, // 开发环境设为 false(HTTPS 环境设为 true)
      path: '/', // 生效路径(/ 表示全站)
      sameSite: 'lax' // 防止 CSRF 攻击
    }
  );
  ctx.body = { code: 200, msg: "Cookie 设置成功" };
});

// 2. 获取 Cookie
router.get('/cookie/get', async (ctx) => {
  const username = ctx.cookies.get('username');
  ctx.body = {
    code: 200,
    msg: "Cookie 获取成功",
    data: { username }
  };
});

// 3. 删除 Cookie
router.get('/cookie/delete', async (ctx) => {
  ctx.cookies.set('username', '', { maxAge: 0 }); // 设置 maxAge 为 0 即删除
  ctx.body = { code: 200, msg: "Cookie 删除成功" };
});

app.use(router.routes());

app.listen(port, () => {
  console.log(`Cookie 服务器启动:http://localhost:${port}`);
});

测试 Cookie

  1. 访问 http://localhost:8008/cookie/set → 设置 Cookie;
  2. 访问 http://localhost:8008/cookie/get → 获取 Cookie,输出 {username: "张三"}
  3. 访问 http://localhost:8008/cookie/delete → 删除 Cookie,再次获取则为 undefined

第十章 session

安装 Session 中间件

Koa 原生不支持 Session,需安装 koa-session

npm install koa-session

Session 配置示例

import Koa from 'koa'
import Router from '@koa/router'
import session  from 'koa-session'

const app = new Koa();
const router = new Router();
const port = 8008;

// 1. 配置 Session 密钥(生产环境需改为随机字符串)
app.keys = ['dengruicode_secret_key'];

// 2. Session 配置
const CONFIG = {
  key: 'koa:sess', // Session Cookie 名称
  maxAge: 24 * 60 * 60 * 1000, // 过期时间 1 天
  autoCommit: true,
  overwrite: true,
  httpOnly: true, // 仅服务端访问
  signed: true, // 签名 Cookie,防止篡改
  rolling: false, // 不刷新过期时间
  renew: false, // 快过期时自动续期
  secure: false, // 开发环境 false
  sameSite: 'lax'
};

// 3. 注册 Session 中间件
app.use(session(CONFIG, app));

// 4. Session 操作
// 设置 Session
router.get('/session/set', async (ctx) => {
  ctx.session.user = {
    id: 1,
    name: "张三",
    age: 20
  };
  ctx.body = { code: 200, msg: "Session 设置成功" };
});

// 获取 Session
router.get('/session/get', async (ctx) => {
  const user = ctx.session.user;
  ctx.body = {
    code: 200,
    msg: "Session 获取成功",
    data: { user }
  };
});

// 删除 Session
router.get('/session/delete', async (ctx) => {
  ctx.session = null; // 清空 Session
  ctx.body = { code: 200, msg: "Session 删除成功" };
});

app.use(router.routes());

app.listen(port, () => {
  console.log(`Session 服务器启动:http://localhost:${port}`);
});

测试 Session

  1. 访问 http://localhost:8008/session/set → 设置 Session;
  2. 访问 http://localhost:8008/session/get → 获取 Session,输出用户信息;
  3. 访问 http://localhost:8008/session/delete → 清空 Session,再次获取则为 undefined

注意:koa-session 是基于 Cookie 的内存 Session,生产环境建议使用 koa-redis 将 Session 存储到 Redis,避免服务重启丢失数据。

第十一章 jwt

安装 JWT 依赖

npm install jsonwebtoken koa-jwt
  • jsonwebtoken:生成 / 解析 JWT 令牌;
  • koa-jwt:验证 JWT 令牌的中间件。

JWT 完整示例

import Koa from 'koa'
import Router from '@koa/router'
import jwt  from 'jsonwebtoken'
import koaJwt  from 'koa-jwt'

const app = new Koa();
const router = new Router();
const port = 8008;

// 1. JWT 密钥(生产环境需加密存储)
const JWT_SECRET = 'dengruicode_jwt_secret';
// JWT 过期时间:1 小时(秒)
const JWT_EXPIRES_IN = 3600;

// 2. 登录接口:生成 JWT 令牌
router.post('/api/login', async (ctx) => {
  // 模拟验证用户名密码(生产环境需查数据库)
  const { username, password } = ctx.request.body;
  if (username === 'admin' && password === '123456') {
    // 生成 JWT 令牌
    const token = jwt.sign(
      { id: 1, username }, // 载荷:存储用户信息(不要存敏感数据)
      JWT_SECRET,
      { expiresIn: JWT_EXPIRES_IN }
    );
    ctx.body = {
      code: 200,
      msg: "登录成功",
      data: { token }
    };
  } else {
    ctx.status = 401;
    ctx.body = { code: 401, msg: "用户名或密码错误" };
  }
});

// 3. 受保护的接口:需要 JWT 验证
// koa-jwt 中间件会自动解析 Authorization 头中的 token
app.use(koaJwt({ secret: JWT_SECRET }).unless({
  path: [/^/api/login/] // 排除登录接口,无需验证
}));

// 4. 获取用户信息接口(需验证 JWT)
router.get('/api/user/info', async (ctx) => {
  // ctx.state.user 是 koa-jwt 解析后的 JWT 载荷
  const { id, username } = ctx.state.user;
  ctx.body = {
    code: 200,
    msg: "获取用户信息成功",
    data: { id, username }
  };
});

app.use(router.routes());

// 5. JWT 错误处理
app.use(async (ctx, next) => {
  try {
    await next();
  } catch (err) {
    if (err.status === 401) {
      ctx.status = 401;
      ctx.body = { code: 401, msg: "token 无效或过期" };
    } else {
      throw err;
    }
  }
});

app.listen(port, () => {
  console.log(`JWT 服务器启动:http://localhost:${port}`);
});

测试 JWT

步骤 1:登录获取 token

curl -X POST -d "username=admin&password=123456" http://localhost:8008/api/login
# 响应:{"code":200,"msg":"登录成功","data":{"token":"xxx.xxx.xxx"}}

步骤 2:携带 token 访问受保护接口

curl -H "Authorization: Bearer 你的token" http://localhost:8008/api/user/info
# 响应:{"code":200,"msg":"获取用户信息成功","data":{"id":1,"username":"admin"}}

步骤 3:token 无效 / 过期测试

携带错误 token 或过期 token 访问,会返回 {"code":401,"msg":"token 无效或过期"}

总结

  1. 核心流程:Koa 开发的核心是「中间件 + 路由」,所有功能(跨域、上传、JWT)都通过中间件扩展;

  2. 关键依赖@koa/router(路由)、koa-body(POST / 上传)、@koa/cors(跨域)、koa-session(Session)、jsonwebtoken/koa-jwt(JWT);

  3. 生产建议

    • Session/JWT 密钥需随机生成并加密存储;

    • 文件上传需限制大小和类型,防止恶意上传;

    • 跨域需指定具体域名,而非 *

    • JWT 载荷不要存敏感数据,过期时间不宜过长。

主管:”人家 Node 框架都用 Nest.js 了 , 你怎么还在用 Express ?“

我反驳主管道 : “我自己做项目做着玩 ! 你管我用哪一个 !”

回家之后 , 我开始好奇那么多 Node 框架 , 到底有什么区别啊?

Node.js Web 框架各式各样 , 下面简单的介绍一下这些 Node.js Web 框架 !

一、分类

Node.js Web 框架主要分 3 类:

分类 核心特点 代表框架 适用场景
极简核心框架 仅封装 HTTP 基础能力,无冗余功能 Express、Koa 中小型 API、自定义业务系统
全栈 / 企业级框架 内置路由、ORM、验证、鉴权等全套能力 NestJS、AdonisJS 大型企业应用、团队协作项目
高性能框架 基于异步 I/O/ 编译优化,极致性能 Fastify、Hapi 高并发 API、微服务
特殊场景框架 针对特定场景优化(如 SSR、低代码) Next.js、Nuxt.js(Node 端)、Sails.js 前端 SSR、低代码平台

二、主流框架详细介绍

⚠️ : 排名不分先后顺序

1. Express(最经典的极简框架)

  • 核心定位:Node.js Web 框架的 “鼻祖”,极简、灵活,无内置冗余功能,生态最丰富。

  • 核心特性

    • 中间件机制(线性中间件,req -> 中间件1 -> 中间件2 -> res);
    • 简洁的路由系统;
    • 无内置 ORM / 验证,需手动集成第三方库(如 mongooseexpress-validator)。
  • 示例代码

    const express = require('express');
    const app = express();
    
    // 中间件
    app.use(express.json());
    
    // 路由
    app.get('/api/user', (req, res) => {
      res.json({ name: '张三', age: 20 });
    });
    
    app.listen(3000, () => console.log('Express 启动在 3000 端口'));
    
  • 优点:生态极全(几乎所有 Node 库都兼容)、学习成本低、灵活度高;

  • 缺点:回调嵌套(易出现 “回调地狱”)、无内置类型支持(TS 需手动配置)、无统一规范(团队协作易混乱);

  • 适用场景:中小型 API 服务、快速原型开发、个人项目。

2. Koa(Express 团队升级版)

  • 核心定位:Express 原团队开发,解决 Express 回调地狱问题,基于 async/await 重构。

  • 核心特性

    • 洋葱模型中间件(中间件可双向执行,如 “请求进来执行 -> 响应出去再执行”);
    • 原生支持 async/await,无回调地狱;
    • 比 Express 更精简(甚至没有内置路由,需装 koa-router)。
  • 示例代码

    const Koa = require('koa');
    const koaRouter = require('koa-router');
    const koaBody = require('koa-body');
    
    const app = new Koa();
    const router = new koaRouter();
    
    // 洋葱模型中间件
    app.use(async (ctx, next) => {
      console.log('请求开始');
      await next(); // 执行下一个中间件
      console.log('请求结束'); // 响应时执行
    });
    
    app.use(koaBody());
    router.get('/api/user', async (ctx) => {
      ctx.body = { name: '张三', age: 20 };
    });
    
    app.use(router.routes());
    app.listen(3000, () => console.log('Koa 启动在 3000 端口'));
    
  • 优点:异步体验好、洋葱模型灵活(适合日志 / 鉴权 / 异常捕获)、轻量;

  • 缺点:生态比 Express 略少、需手动集成更多第三方库;

  • 适用场景:中小型 API 服务、需要灵活中间件的场景、嫌弃 Express 回调的项目。

3. NestJS(企业级 TypeScript 框架)

  • 核心定位:对标 Spring Boot,基于 TypeScript,强调模块化、依赖注入,适合大型团队协作。

  • 核心特性

    • 强制 TypeScript 开发,类型安全;
    • 模块化架构(Module + Controller + Service);
    • 内置依赖注入、拦截器、管道、守卫(鉴权)、过滤器;
    • 兼容 Express/Koa,可无缝集成第三方库;
    • 支持微服务、GraphQL、WebSocket。
  • 示例代码

    // user.controller.ts
    import { Controller, Get } from '@nestjs/common';
    import { UserService } from './user.service';
    
    @Controller('api/user')
    export class UserController {
      constructor(private readonly userService: UserService) {}
    
      @Get()
      getUser() {
        return this.userService.getUser();
      }
    }
    
    // user.service.ts
    import { Injectable } from '@nestjs/common';
    
    @Injectable()
    export class UserService {
      getUser() {
        return { name: '张三', age: 20 };
      }
    }
    
  • 优点:规范统一、类型安全、适合大型项目 / 团队、生态完善(官方封装了大量企业级能力);

  • 缺点:学习成本高、入门门槛高、小型项目用着 “重”;

  • 适用场景:大型企业应用、微服务、团队协作项目、需要强类型的项目。

4. Fastify(高性能极简框架)

  • 核心定位:极致性能,比 Express 快 2-3 倍,专为高并发 API 设计。

  • 核心特性

    • 基于 JSON Schema 验证请求参数,性能优于传统验证库;
    • 内置日志、压缩、路由缓存,无需额外配置;
    • 兼容 Express 中间件;
    • 支持 TypeScript。
  • 示例代码

    const fastify = require('fastify')({ logger: true });
    
    // 路由 + 参数验证
    fastify.get('/api/user', {
      schema: {
        querystring: {
          age: { type: 'number' }
        }
      }
    }, async (request, reply) => {
      return { name: '张三', age: request.query.age || 20 };
    });
    
    fastify.listen({ port: 3000 }, (err) => {
      if (err) throw err;
      console.log('Fastify 启动在 3000 端口');
    });
    
  • 优点:性能极高、内置功能丰富(无需装大量中间件)、轻量;

  • 缺点:生态比 Express 小、部分特性(如 Schema 验证)有学习成本;

  • 适用场景:高并发 API、微服务、对性能要求高的项目。

5. Hapi(稳定的企业级框架)

“还记得当初在 沃尔玛 买了虾 , 自己回家自己做 鸡油炒河虾仁 , 艾玛 , 老香了!!! ”

  • 核心定位:由 Walmart ( 沃尔玛 ) 开发,强调配置优于编码,适合稳定的企业级服务。

  • 核心特性

    • 内置路由、验证、缓存、日志,无需第三方库;
    • 插件化架构,扩展能力强;
    • 稳定性极高(适合金融 / 电商等核心系统)。
  • 优点:稳定、内置功能全、安全性高;

  • 缺点:学习成本高、灵活性低、性能不如 Fastify;

  • 适用场景:金融 / 电商等核心系统、对稳定性要求极高的项目。

6. Next.js(前端 SSR/SSG 框架,Node 端核心)

  • 核心定位:React 生态的全栈框架,Node 端负责服务端渲染(SSR)、静态生成(SSG)。

  • 核心特性

    • 服务端渲染(提升 SEO、首屏加载速度);
    • 自动路由(基于文件系统);
    • 内置 API 路由(无需额外搭后端);
    • 支持静态生成、增量静态再生。
  • 适用场景:React 前端项目、需要 SEO 的网站(如博客、电商)、全栈 React 应用。

7. Sails.js(低代码 / 快速开发框架)

  • 核心定位:对标 Ruby on Rails,内置 ORM、蓝图 API、实时通信,适合快速开发全栈应用。

  • 核心特性

    • 自动生成 CRUD API(蓝图路由);
    • 内置 Waterline ORM(支持多数据库);
    • 支持 WebSocket 实时通信;
  • 优点:开发速度极快、低代码;

  • 缺点:灵活性低、定制化成本高;

  • 适用场景:快速原型开发、低代码平台、小型全栈应用。

8. AdonisJS(Node.js 版的 Laravel,全栈企业级框架)

  • 核心定位:对标 PHP 界的 Laravel,是 Node.js 生态中 “开箱即用” 的全栈框架,内置全套企业级能力,强调 “约定优于配置”。

  • 核心特性

    • 内置 ORM(Lucid ORM):支持 MySQL、PostgreSQL 等,无需手动集成第三方 ORM;
    • 内置身份验证(用户注册 / 登录 / 权限)、表单验证、CSRF 保护;
    • 支持 MVC 架构、路由分组、中间件、任务调度;
    • 原生支持 TypeScript,类型安全;
    • 内置模板引擎(Edge),也支持前后端分离;
  • 示例代码(核心路由 + ORM)

    // start/routes.ts
    import Route from '@ioc:Adonis/Core/Route'
    import User from 'App/Models/User'
    
    // 路由 + 数据库查询
    Route.get('/api/user', async () => {
      const user = await User.find(1) // Lucid ORM 查用户
      return { name: user?.name, age: user?.age }
    })
    
    // 表单验证
    Route.post('/api/user', async ({ request }) => {
      const data = request.validate({
        schema: {
          name: schema.string(),
          age: schema.number()
        }
      })
      await User.create(data) // 新增用户
      return { success: true }
    })
    
  • 优点:开箱即用(无需装大量依赖)、Laravel 开发者易上手、规范统一、内置安全特性;

  • 缺点:生态比 Express/NestJS 小、灵活性略低、国内使用较少(中文文档有限);

  • 适用场景:全栈 Node.js 应用、Laravel 转 Node 开发的团队、中小型企业应用、需要快速搭建带数据库的业务系统。

9. Nuxt.js(Vue 生态全栈框架,Node 端负责 SSR/SSG)

  • 核心定位:Vue 生态的官方全栈框架,基于 Vue + Node.js 实现服务端渲染(SSR)、静态站点生成(SSG),解决 Vue 单页应用 SEO 差的问题。

  • 核心特性

    • 自动路由(基于 pages 目录,无需手动配置路由);
    • 服务端渲染(SSR)、静态生成(SSG)、增量静态再生(ISR);
    • 内置 API 路由(server/api 目录,无需额外搭后端服务);
    • 支持 Vue3 + TypeScript、自动代码分割、缓存优化;
    • 集成 Pinia(状态管理)、Nuxt Modules(生态插件);
  • 示例代码(核心用法)

    <!-- pages/api/user.vue (页面路由) -->
    <template>
      <div>{{ user.name }}</div>
    </template>
    
    <script setup lang="ts">
    // 服务端获取数据(SSR)
    const { data: user } = await useAsyncData('user', () => 
      $fetch('/api/user') // 调用内置 API 路由
    )
    </script>
    
    // server/api/user.ts (内置 API 路由)
    export default defineEventHandler(() => {
      return { name: '张三', age: 20 }
    })
    
  • 优点:Vue 开发者无缝上手、解决 SEO 问题、全栈一体化(前端 + Node 端)、生态完善;

  • 缺点:仅适配 Vue 技术栈、Node 端逻辑定制化能力有限、大型项目需深入理解其生命周期;

  • 适用场景:Vue 全栈应用、需要 SEO 的网站(博客 / 电商 / 官网)、静态站点生成、中小型 Vue 项目。

10. Egg.js(阿里开源,企业级 Node.js 框架)

  • 核心定位:阿里开源的企业级框架,基于 Express/Koa 封装,强调 “约定优于配置”,适合中大型团队协作。

  • 核心特性

    • 基于 Koa2(洋葱模型),兼容 Koa/Express 中间件;
    • 内置多进程模型(Master + Worker),自动利用多核 CPU;
    • 插件化架构(如 egg-mysql、egg-redis),生态丰富(阿里官方维护);
    • 支持 TypeScript、单元测试、日志、监控;
    • 规范的目录结构(controller/service/middleware/config),团队协作友好;
  • 示例代码

    // app/controller/user.js
    const { Controller } = require('egg');
    
    class UserController extends Controller {
      async index() {
        const { ctx } = this;
        // 调用 service 层
        const user = await ctx.service.user.getUser();
        ctx.body = user;
      }
    }
    
    module.exports = UserController;
    
    // app/service/user.js
    const { Service } = require('egg');
    
    class UserService extends Service {
      async getUser() {
        // 用 egg-mysql 查数据库
        return await this.app.mysql.get('user', { id: 1 });
      }
    }
    
    module.exports = UserService;
    
  • 优点:阿里背书、规范统一、多进程性能优、国内生态完善(中文文档 / 社区)、适合团队协作;

  • 缺点:灵活性低于 Express/Koa、学习成本中等、小型项目用着 “重”;

  • 适用场景:中大型企业应用、阿里系技术栈项目、国内团队协作项目、需要多进程优化的 Node 服务。

三、 对比

框架 学习成本 性能 生态 类型支持 适用规模 核心优势 技术栈 / 定位
Express 中等 极丰富 需手动配 小 / 中 灵活、生态全、入门快 极简核心框架
Koa 中等 丰富 需手动配 小 / 中 洋葱模型、async/await 极简核心框架(Express 升级版)
NestJS 中等 丰富 原生 TS 中 / 大 规范、企业级、团队协作 企业级 TS 框架
Fastify 极高 中等 原生 TS 小 / 中 / 大 极致性能、内置功能全 高性能极简框架
Hapi 中高 中等 需手动配 中 / 大 稳定、安全、企业级 企业级配置优先框架
Next.js 中等 极丰富 原生 TS 小 / 中 / 大 React SSR、全栈一体化 React 全栈框架
Sails.js 中等 中等 需手动配 低代码、开发速度快 低代码全栈框架
AdonisJS 中等 中等 原生 TS 小 / 中 Laravel 风格、开箱即用 全栈企业级框架(Node 版 Laravel)
Nuxt.js 中等 极丰富 原生 TS 小 / 中 / 大 Vue SSR、全栈一体化、SEO 优 Vue 全栈框架
Egg.js 中高 丰富 需手动配 中 / 大 阿里背书、多进程、国内生态好 企业级框架(基于 Koa)

四、选型建议

  1. 个人 / 小型项目、快速开发:选 Express(生态全)或 Koa(异步体验好);
  2. 高并发 API、微服务:选 Fastify(性能第一);
  3. 大型企业应用、团队协作:选 NestJS(TS + 规范)或 Hapi(稳定);
  4. React 全栈、需要 SEO:选 Next.js;
  5. 低代码、快速原型:选 Sails.js。

总结

  1. 核心维度:选型优先看「项目规模 + 团队技术栈 + 性能要求」,小型项目别用重框架(如 NestJS),大型项目别用太灵活的框架(如 Express);
  2. 生态优先级:如果需要集成大量第三方库,Express / Koa / Next.js 是首选;
  3. 性能优先级:高并发场景直接选 Fastify;
  4. 团队协作:大型团队优先 NestJS(强规范),避免 Express 因灵活导致的代码混乱。

okokok , 这个文章到这里就结束了 , 我们有缘再会 😁😁😁 !!!

❌