Skip to content

Node.js Web 框架对比指南

目录

Express

简介

Express 是最流行的 Node.js Web 应用框架,提供了一套简洁而灵活的功能,用于构建 Web 和移动应用程序。它是许多其他流行 Web 框架的基础。

核心特性

  1. 中间件系统
  2. 路由系统
  3. 静态文件服务
  4. 模板引擎支持
  5. 错误处理

基本使用

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 帮助你摆脱回调地狱,并提供了一个优雅的中间件组合机制。

核心特性

  1. 现代化的中间件架构
  2. 基于 async/await 的流程控制
  3. 更好的错误处理
  4. 轻量级设计
  5. 请求/响应对象增强

基本使用

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(函数式响应式编程)的元素。

核心特性

  1. 模块化架构
  2. 依赖注入系统
  3. 装饰器支持
  4. TypeScript 支持
  5. WebSocket 支持
  6. 微服务支持
  7. REST API 支持
  8. 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 {}

框架对比

性能对比

特性ExpressKoaNext.js
启动时间最快较慢
内存占用最低较高
请求处理速度
构建时间不需要不需要较长

功能对比

特性ExpressKoaNext.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;
  }
  // 处理请求
}