Appearance
Node.js Web 框架对比指南
目录
Express
简介
Express 是最流行的 Node.js Web 应用框架,提供了一套简洁而灵活的功能,用于构建 Web 和移动应用程序。它是许多其他流行 Web 框架的基础。
核心特性
- 中间件系统
- 路由系统
- 静态文件服务
- 模板引擎支持
- 错误处理
基本使用
javascript
const express = require("express");
const app = express();
// 中间件
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// 路由
app.get("/", (req, res) => {
res.send("Hello World!");
});
app.post("/api/users", (req, res) => {
const user = req.body;
// 处理用户数据
res.json({ success: true, user });
});
// 错误处理
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send("Something broke!");
});
app.listen(3000, () => {
console.log("Server is running on port 3000");
});
中间件示例
javascript
// 认证中间件
const auth = (req, res, next) => {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ error: "No token provided" });
}
// 验证 token
try {
const decoded = jwt.verify(token, "secret");
req.user = decoded;
next();
} catch (err) {
res.status(401).json({ error: "Invalid token" });
}
};
// 使用中间件
app.get("/protected", auth, (req, res) => {
res.json({ user: req.user });
});
路由模块化
javascript
// routes/users.js
const express = require("express");
const router = express.Router();
router.get("/", (req, res) => {
res.json({ users: [] });
});
router.post("/", (req, res) => {
// 创建用户
});
module.exports = router;
// app.js
const usersRouter = require("./routes/users");
app.use("/api/users", usersRouter);
Koa
简介
Koa 是由 Express 团队开发的新一代 Web 框架,旨在成为一个更小、更富有表现力、更健壮的基础框架。通过利用 async/await,Koa 帮助你摆脱回调地狱,并提供了一个优雅的中间件组合机制。
核心特性
- 现代化的中间件架构
- 基于 async/await 的流程控制
- 更好的错误处理
- 轻量级设计
- 请求/响应对象增强
基本使用
javascript
const Koa = require("koa");
const Router = require("@koa/router");
const bodyParser = require("koa-bodyparser");
const app = new Koa();
const router = new Router();
// 中间件
app.use(bodyParser());
// 错误处理
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
ctx.status = err.status || 500;
ctx.body = { error: err.message };
ctx.app.emit("error", err, ctx);
}
});
// 路由
router.get("/", async (ctx) => {
ctx.body = "Hello World";
});
router.post("/api/users", async (ctx) => {
const user = ctx.request.body;
ctx.body = { success: true, user };
});
app.use(router.routes()).use(router.allowedMethods());
app.listen(3000, () => {
console.log("Server running on port 3000");
});
中间件示例
javascript
// 认证中间件
const auth = async (ctx, next) => {
const token = ctx.headers.authorization;
if (!token) {
ctx.throw(401, "No token provided");
}
try {
const decoded = jwt.verify(token, "secret");
ctx.state.user = decoded;
await next();
} catch (err) {
ctx.throw(401, "Invalid token");
}
};
// 使用中间件
router.get("/protected", auth, async (ctx) => {
ctx.body = { user: ctx.state.user };
});
中间件组合
javascript
const compose = require("koa-compose");
async function logger(ctx, next) {
const start = Date.now();
await next();
const ms = Date.now() - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
}
async function responseTime(ctx, next) {
const start = Date.now();
await next();
const ms = Date.now() - start;
ctx.set("X-Response-Time", `${ms}ms`);
}
app.use(compose([logger, responseTime]));
Nest.js
简介
Nest.js 是一个用于构建高效、可扩展的 Node.js 服务器端应用程序的框架。它使用渐进式 JavaScript,使用 TypeScript 构建,并结合了 OOP(面向对象编程)、FP(函数式编程)和 FRP(函数式响应式编程)的元素。
核心特性
- 模块化架构
- 依赖注入系统
- 装饰器支持
- TypeScript 支持
- WebSocket 支持
- 微服务支持
- REST API 支持
- GraphQL 支持
基本使用
typescript
// app.controller.ts
import { Controller, Get } from "@nestjs/common";
import { AppService } from "./app.service";
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}
// app.service.ts
import { Injectable } from "@nestjs/common";
@Injectable()
export class AppService {
getHello(): string {
return "Hello World!";
}
}
// app.module.ts
import { Module } from "@nestjs/common";
import { AppController } from "./app.controller";
import { AppService } from "./app.service";
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
// main.ts
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();
REST API 示例
typescript
// users/user.entity.ts
export class User {
id: number;
name: string;
email: string;
}
// users/users.controller.ts
import {
Controller,
Get,
Post,
Body,
Param,
Delete,
Put,
} from "@nestjs/common";
import { UsersService } from "./users.service";
import { CreateUserDto, UpdateUserDto } from "./dto";
@Controller("users")
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}
@Get()
findAll() {
return this.usersService.findAll();
}
@Get(":id")
findOne(@Param("id") id: string) {
return this.usersService.findOne(+id);
}
@Put(":id")
update(@Param("id") id: string, @Body() updateUserDto: UpdateUserDto) {
return this.usersService.update(+id, updateUserDto);
}
@Delete(":id")
remove(@Param("id") id: string) {
return this.usersService.remove(+id);
}
}
中间件示例
typescript
// auth.middleware.ts
import { Injectable, NestMiddleware } from "@nestjs/common";
import { Request, Response, NextFunction } from "express";
@Injectable()
export class AuthMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ message: "Unauthorized" });
}
// 验证 token
try {
// const decoded = jwt.verify(token, 'secret');
// req['user'] = decoded;
next();
} catch (err) {
return res.status(401).json({ message: "Invalid token" });
}
}
}
// app.module.ts
import { Module, NestModule, MiddlewareConsumer } from "@nestjs/common";
import { AuthMiddleware } from "./auth.middleware";
@Module({})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(AuthMiddleware).forRoutes("protected");
}
}
管道和验证
typescript
// create-user.dto.ts
import { IsString, IsEmail, MinLength } from 'class-validator';
export class CreateUserDto {
@IsString()
@MinLength(2)
name: string;
@IsEmail()
email: string;
}
// users.controller.ts
import { Body, UsePipes, ValidationPipe } from '@nestjs/common';
@Post()
@UsePipes(new ValidationPipe())
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}
异常过滤器
typescript
// http-exception.filter.ts
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
} from "@nestjs/common";
import { Response } from "express";
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const status = exception.getStatus();
const message = exception.message;
response.status(status).json({
statusCode: status,
message,
timestamp: new Date().toISOString(),
});
}
}
// main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new HttpExceptionFilter());
await app.listen(3000);
}
守卫
typescript
// auth.guard.ts
import { Injectable, CanActivate, ExecutionContext } from "@nestjs/common";
import { Observable } from "rxjs";
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(
context: ExecutionContext
): boolean | Promise<boolean> | Observable<boolean> {
const request = context.switchToHttp().getRequest();
return this.validateRequest(request);
}
private validateRequest(request: any): boolean {
// 在这里添加你的验证逻辑
return true;
}
}
// users.controller.ts
import { UseGuards } from "@nestjs/common";
@UseGuards(AuthGuard)
@Controller("users")
export class UsersController {}
拦截器
typescript
// logging.interceptor.ts
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
} from "@nestjs/common";
import { Observable } from "rxjs";
import { tap } from "rxjs/operators";
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const now = Date.now();
return next
.handle()
.pipe(tap(() => console.log(`执行时间: ${Date.now() - now}ms`)));
}
}
// users.controller.ts
import { UseInterceptors } from "@nestjs/common";
@UseInterceptors(LoggingInterceptor)
@Controller("users")
export class UsersController {}
数据库集成 (TypeORM)
typescript
// app.module.ts
import { TypeOrmModule } from "@nestjs/typeorm";
@Module({
imports: [
TypeOrmModule.forRoot({
type: "mysql",
host: "localhost",
port: 3306,
username: "root",
password: "root",
database: "test",
entities: [],
synchronize: true,
}),
],
})
export class AppModule {}
// user.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from "typeorm";
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column()
email: string;
}
// users.module.ts
import { TypeOrmModule } from "@nestjs/typeorm";
import { User } from "./user.entity";
@Module({
imports: [TypeOrmModule.forFeature([User])],
providers: [UsersService],
controllers: [UsersController],
})
export class UsersModule {}
框架对比
性能对比
特性 | Express | Koa | Next.js |
---|---|---|---|
启动时间 | 快 | 最快 | 较慢 |
内存占用 | 低 | 最低 | 较高 |
请求处理速度 | 快 | 快 | 快 |
构建时间 | 不需要 | 不需要 | 较长 |
功能对比
特性 | Express | Koa | Next.js |
---|---|---|---|
路由系统 | 内置 | 插件 | 文件系统 |
中间件 | 线性 | 洋葱模型 | 混合 |
模板引擎 | 多种选择 | 插件 | React |
SSR | 手动实现 | 手动实现 | 内置 |
静态文件 | 内置 | 插件 | 内置 |
API 支持 | 完整 | 精简 | 内置 |
使用场景
Express 适用于
- RESTful API 服务
- 传统的 Web 应用
- 小型到中型项目
- 需要完整功能集的项目
Koa 适用于
- 需要精细控制的项目
- 现代化的 Web 应用
- 对性能要求极高的项目
- 喜欢简洁设计的开发者
Next.js 适用于
- React 单页应用
- 需要 SEO 的网站
- 大型 Web 应用
- 需要静态站点生成的项目
最佳实践
Express 最佳实践
javascript
// 1. 使用环境变量
require("dotenv").config();
// 2. 安全中间件
const helmet = require("helmet");
app.use(helmet());
// 3. 压缩响应
const compression = require("compression");
app.use(compression());
// 4. 请求限制
const rateLimit = require("express-rate-limit");
app.use(
rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100, // 限制每个IP 100个请求
})
);
// 5. 错误处理
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send("Something broke!");
});
Koa 最佳实践
javascript
// 1. 结构化错误处理
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
ctx.status = err.status || 500;
ctx.body = {
message: err.message,
error: process.env.NODE_ENV === "development" ? err : {},
};
ctx.app.emit("error", err, ctx);
}
});
// 2. 模块化路由
const combineRouters = require("koa-combine-routers");
const userRouter = require("./routes/users");
const postRouter = require("./routes/posts");
const router = combineRouters(userRouter, postRouter);
// 3. 参数验证
const validate = require("koa-validate");
Next.js 最佳实践
javascript
// 1. 自定义 App 组件
// pages/_app.js
import { Provider } from "react-redux";
import { store } from "../store";
function MyApp({ Component, pageProps }) {
return (
<Provider store={store}>
<Component {...pageProps} />
</Provider>
);
}
// 2. 性能优化
// 使用 Image 组件
import Image from "next/image";
function MyImage() {
return (
<Image
src="/my-image.jpg"
alt="My Image"
width={500}
height={300}
priority
/>
);
}
// 3. API 路由保护
// pages/api/protected.js
import { getSession } from "next-auth/react";
export default async function handler(req, res) {
const session = await getSession({ req });
if (!session) {
res.status(401).json({ error: "Unauthorized" });
return;
}
// 处理请求
}