NextJs的后端目录结构说明

Table of Contents

以下是 Next.js 项目中后端 API 的目录结构及文件说明(涵盖 App RouterPages Router 两种模式)。根据最新实践,推荐优先使用 App Router 的 API 路由设计

目录结构(App Router 模式)

my-next-app/
├── app/
│   ├── api/                    # API 路由目录(核心目录)
│   │   ├── users/             # 用户相关 API 端点
│   │   │   ├── route.ts       # `/api/users` 的路由处理
│   │   │   └── [id]/          # 动态路由(如 `/api/users/123`)
│   │   │       └── route.ts
│   │   ├── products/          # 商品相关 API
│   │   │   └── route.ts
│   │   └── auth/              # 认证相关 API
│   │       └── route.ts
├── lib/
│   ├── db.ts                  # 数据库连接工具
│   └── api-utils.ts           # API 通用工具函数
├── middleware.ts              # 全局中间件(如身份验证)
└── ...

关键文件说明(App Router)

1. app/api/[path]/route.ts

  • 作用:定义 API 端点,支持 GET/POST/PUT/DELETE 等方法。

  • 文件命名规则:必须为 route.ts(或 route.js)。

  • 示例代码

    // app/api/users/route.ts
    import { NextResponse } from 'next/server';
    import { db } from '@/lib/db';
    
    // GET /api/users
    export async function GET() {
      const users = await db.user.findMany();
      return NextResponse.json(users);
    }
    
    // POST /api/users
    export async function POST(request: Request) {
      const data = await request.json();
      const newUser = await db.user.create({ data });
      return NextResponse.json(newUser, { status: 201 });
    }
    

2. 动态路由 app/api/users/[id]/route.ts

  • 作用:处理带参数的请求(如 /api/users/123)。
  • 参数获取
    export async function GET(
      request: Request,
      { params }: { params: { id: string } }
    ) {
      const userId = params.id; // '123'
      // ...
    }
    

目录结构(Pages Router 模式 - 旧版)

my-next-app/
├── pages/
│   └── api/                  # API 路由目录
│       ├── users.ts          # `/api/users`
│       └── products/
│           ├── index.ts      # `/api/products`
│           └── [id].ts       # `/api/products/123`
└── ...

关键文件说明(Pages Router)

1. pages/api/[path].ts

  • 作用:通过默认导出的函数处理请求。

  • 示例代码

    // pages/api/users.ts
    import { NextApiRequest, NextApiResponse } from 'next';
    import { db } from '@/lib/db';
    
    export default async function handler(
      req: NextApiRequest,
      res: NextApiResponse
    ) {
      if (req.method === 'GET') {
        const users = await db.user.findMany();
        res.status(200).json(users);
      } else {
        res.setHeader('Allow', ['GET']);
        res.status(405).end('Method Not Allowed');
      }
    }
    

通用最佳实践

1. 分层架构

  • 推荐结构
    app/
    └── api/
        └── users/
            ├── route.ts        # 路由入口
            ├── controller.ts   # 业务逻辑
            ├── schema.ts       # 请求验证(如 Zod)
            └── types.ts        # 类型定义
    

2. 请求验证

  • 使用 Zod 或 Yup

    // app/api/users/route.ts
    import { z } from 'zod';
    
    const createUserSchema = z.object({
      name: z.string().min(2),
      email: z.string().email(),
    });
    
    export async function POST(request: Request) {
      const body = await request.json();
      const validation = createUserSchema.safeParse(body);
      if (!validation.success) {
        return NextResponse.json(validation.error.errors, { status: 400 });
      }
      // 处理合法请求...
    }
    

3. 错误处理

  • 统一错误格式

    // lib/api-utils.ts
    export class APIError extends Error {
      constructor(
        public statusCode: number,
        public message: string,
        public details?: any
      ) {
        super(message);
      }
    }
    
    // 在路由中使用
    export async function GET() {
      try {
        // ...
      } catch (err) {
        if (err instanceof APIError) {
          return NextResponse.json(
            { error: err.message, details: err.details },
            { status: err.statusCode }
          );
        }
        return NextResponse.json(
          { error: 'Internal Server Error' },
          { status: 500 }
        );
      }
    }
    

中间件集成

1. 全局中间件 (middleware.ts)

  • 作用:处理跨路由的通用逻辑(如身份验证、CORS)。

  • 示例(身份验证):

    // middleware.ts
    import { NextResponse } from 'next/server';
    
    export function middleware(request: NextRequest) {
      const token = request.cookies.get('authToken');
      const isAPIRoute = request.nextUrl.pathname.startsWith('/api');
    
      // 拦截未授权的 API 请求
      if (isAPIRoute && !token) {
        return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
      }
    
      return NextResponse.next();
    }
    

2. 路由级中间件

  • 自定义中间件链

    // app/api/users/route.ts
    import { withAuth } from '@/lib/middlewares';
    
    // 组合中间件
    const handler = async (request: Request) => {
      // 主逻辑
    };
    
    export const GET = withAuth(handler);
    

环境变量管理

  • 敏感信息(如数据库密码)存储在 .env.local

    # .env.local
    DATABASE_URL="postgresql://user:password@localhost:5432/mydb"
    
  • 在 API 中访问

    // lib/db.ts
    import { Pool } from 'pg';
    
    const pool = new Pool({
      connectionString: process.env.DATABASE_URL,
    });
    

常用工具推荐

  1. 数据库 ORM:Prisma、Drizzle
  2. 请求验证:Zod、Yup
  3. HTTP 客户端fetch(内置)、axios
  4. 身份验证:NextAuth.js、Clerk
  5. API 文档:Swagger UI、Next.js + OpenAPI

完整示例流程

请求POST /api/users

// app/api/users/route.ts
export async function POST(request: Request) {
  // 1. 验证请求体
  const body = await request.json();
  const validation = createUserSchema.safeParse(body);
  if (!validation.success) { /* 返回 400 错误 */ }

  // 2. 数据库操作
  const newUser = await db.user.create({ data: validation.data });

  // 3. 返回响应
  return NextResponse.json(newUser, { status: 201 });
}

总结

Next.js 的 API 路由设计具有以下特点:

  1. 无服务器架构:自动处理服务器部署(Vercel 或其他平台)
  2. 灵活路由:支持动态参数、嵌套路由
  3. 中间件支持:全局或局部拦截请求
  4. 类型安全:与 TypeScript 深度集成
  5. 无缝扩展:可连接数据库、第三方服务

无论是构建简单的 MVP 还是复杂的企业级 API,这种结构都能提供清晰的代码组织和可维护性。

使用 mongodb.com 提供的免费500M mongodb 服务,结果死活连不上。改为用 supabase 的 Postgres 了

明天了解一下 mongodb 和 postgresql 的对比,它们各自的适用场景是怎样的