Skip to content

第10章:API 路由开发(Next.js 内置后端能力)

Next.js 不仅是一个前端框架,还提供了内置的后端能力,通过 API 路由可以直接在 Next.js 项目中创建 API 接口,无需单独搭建后端服务。这使得 Next.js 成为一个全栈框架,非常适合快速开发完整的应用。

10.1 API 路由基础

10.1.1 API 路由目录约定

在 Next.js 14 中,API 路由位于 app/api 目录下,遵循与 App Router 相同的文件系统路由约定。每个 API 路由文件需要导出一个函数,处理特定的 HTTP 请求。

基本结构示例

javascript
// app/api/hello/route.js
export async function GET(request) {
  return new Response('Hello, Next.js!');
}

10.1.2 API 路由文件命名

  • API 路由文件必须命名为 route.jsroute.ts
  • 目录结构对应 API 路径,例如 app/api/users/route.js 对应 /api/users 路径
  • 支持动态路由,例如 app/api/users/[id]/route.js 对应 /api/users/123 路径

10.2 常用请求方法实现

Next.js API 路由支持多种 HTTP 请求方法,通过导出不同的函数来处理:

10.2.1 GET 请求

用于获取数据:

javascript
// app/api/users/route.js
export async function GET(request) {
  // 从数据库获取用户列表
  const users = [
    { id: 1, name: 'Alice' },
    { id: 2, name: 'Bob' }
  ];
  
  return Response.json(users);
}

10.2.2 POST 请求

用于创建数据:

javascript
// app/api/users/route.js
export async function POST(request) {
  const data = await request.json();
  
  // 处理创建用户的逻辑
  const newUser = {
    id: Date.now(),
    ...data
  };
  
  // 模拟保存到数据库
  // db.users.insert(newUser);
  
  return Response.json(newUser, { status: 201 });
}

10.2.3 PUT 请求

用于更新数据:

javascript
// app/api/users/[id]/route.js
export async function PUT(request, { params }) {
  const { id } = params;
  const data = await request.json();
  
  // 处理更新用户的逻辑
  const updatedUser = {
    id: parseInt(id),
    ...data
  };
  
  // 模拟更新数据库
  // db.users.update({ id }, data);
  
  return Response.json(updatedUser);
}

10.2.4 DELETE 请求

用于删除数据:

javascript
// app/api/users/[id]/route.js
export async function DELETE(request, { params }) {
  const { id } = params;
  
  // 处理删除用户的逻辑
  // db.users.delete({ id });
  
  return Response.json({ message: `User ${id} deleted` });
}

10.3 API 路由参数与请求体处理

10.3.1 路径参数

通过 params 对象获取路径参数:

javascript
// app/api/users/[id]/route.js
export async function GET(request, { params }) {
  const { id } = params;
  // 根据 id 获取用户
  return Response.json({ id, name: 'User ' + id });
}

10.3.2 查询参数

通过 request.nextUrl.searchParams 获取查询参数:

javascript
// app/api/users/route.js
export async function GET(request) {
  const searchParams = request.nextUrl.searchParams;
  const page = searchParams.get('page') || 1;
  const limit = searchParams.get('limit') || 10;
  
  // 根据分页参数获取用户列表
  return Response.json({ 
    users: [], 
    pagination: { page, limit } 
  });
}

10.3.3 请求体处理

对于 POST、PUT 等请求,需要解析请求体:

javascript
// app/api/users/route.js
export async function POST(request) {
  try {
    const data = await request.json();
    // 处理数据
    return Response.json({ success: true, data });
  } catch (error) {
    return Response.json({ error: 'Invalid JSON' }, { status: 400 });
  }
}

10.4 API 路由中间件

10.4.1 权限验证中间件

创建一个权限验证中间件:

javascript
// app/api/middleware.js
import { NextResponse } from 'next/server';

export function middleware(request) {
  const token = request.headers.get('authorization')?.split(' ')[1];
  
  if (!token) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }
  
  // 验证 token
  // const isValid = verifyToken(token);
  // if (!isValid) {
  //   return NextResponse.json({ error: 'Invalid token' }, { status: 401 });
  // }
  
  return NextResponse.next();
}

export const config = {
  matcher: '/api/protected/:path*',
};

10.4.2 请求日志中间件

javascript
// app/api/logging-middleware.js
import { NextResponse } from 'next/server';

export function middleware(request) {
  console.log('API Request:', {
    url: request.url,
    method: request.method,
    headers: Object.fromEntries(request.headers),
  });
  
  return NextResponse.next();
}

export const config = {
  matcher: '/api/:path*',
};

10.5 与数据库连接

10.5.1 MongoDB 集成

步骤 1:安装依赖

bash
npm install mongodb

步骤 2:创建数据库连接

javascript
// lib/mongodb.js
import { MongoClient } from 'mongodb';

const uri = process.env.MONGODB_URI;
const options = {
  useNewUrlParser: true,
  useUnifiedTopology: true,
};

let client;
let clientPromise;

if (!uri) {
  throw new Error('Please add your Mongo URI to .env.local');
}

if (process.env.NODE_ENV === 'development') {
  if (!global._mongoClientPromise) {
    client = new MongoClient(uri, options);
    global._mongoClientPromise = client.connect();
  }
  clientPromise = global._mongoClientPromise;
} else {
  client = new MongoClient(uri, options);
  clientPromise = client.connect();
}

export default clientPromise;

步骤 3:在 API 路由中使用

javascript
// app/api/users/route.js
import clientPromise from '@/lib/mongodb';

export async function GET(request) {
  try {
    const client = await clientPromise;
    const db = client.db('nextjs-tutorial');
    
    const users = await db.collection('users').find({}).toArray();
    
    return Response.json(users);
  } catch (error) {
    return Response.json({ error: error.message }, { status: 500 });
  }
}

10.5.2 PostgreSQL 集成

步骤 1:安装依赖

bash
npm install pg

步骤 2:创建数据库连接

javascript
// lib/postgres.js
import { Pool } from 'pg';

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});

export default pool;

步骤 3:在 API 路由中使用

javascript
// app/api/users/route.js
import pool from '@/lib/postgres';

export async function GET(request) {
  try {
    const { rows } = await pool.query('SELECT * FROM users');
    return Response.json(rows);
  } catch (error) {
    return Response.json({ error: error.message }, { status: 500 });
  }
}

10.6 API 路由最佳实践

  1. 错误处理:始终使用 try/catch 捕获错误并返回适当的错误响应
  2. 输入验证:验证请求数据的格式和内容
  3. 安全性:使用参数化查询防止 SQL 注入,验证用户权限
  4. 性能优化:合理使用缓存,避免重复数据库查询
  5. 代码组织:将数据库逻辑和业务逻辑分离,保持 API 路由文件简洁

10.7 实战示例:完整的用户 API

javascript
// app/api/users/route.js
import clientPromise from '@/lib/mongodb';

export async function GET(request) {
  try {
    const client = await clientPromise;
    const db = client.db('nextjs-tutorial');
    
    const users = await db.collection('users').find({}).toArray();
    return Response.json(users);
  } catch (error) {
    return Response.json({ error: error.message }, { status: 500 });
  }
}

export async function POST(request) {
  try {
    const client = await clientPromise;
    const db = client.db('nextjs-tutorial');
    
    const data = await request.json();
    const result = await db.collection('users').insertOne(data);
    
    return Response.json({ 
      ...data, 
      _id: result.insertedId 
    }, { status: 201 });
  } catch (error) {
    return Response.json({ error: error.message }, { status: 500 });
  }
}

// app/api/users/[id]/route.js
import clientPromise from '@/lib/mongodb';
import { ObjectId } from 'mongodb';

export async function GET(request, { params }) {
  try {
    const client = await clientPromise;
    const db = client.db('nextjs-tutorial');
    
    const user = await db.collection('users').findOne({
      _id: new ObjectId(params.id)
    });
    
    if (!user) {
      return Response.json({ error: 'User not found' }, { status: 404 });
    }
    
    return Response.json(user);
  } catch (error) {
    return Response.json({ error: error.message }, { status: 500 });
  }
}

export async function PUT(request, { params }) {
  try {
    const client = await clientPromise;
    const db = client.db('nextjs-tutorial');
    
    const data = await request.json();
    const result = await db.collection('users').updateOne(
      { _id: new ObjectId(params.id) },
      { $set: data }
    );
    
    if (result.matchedCount === 0) {
      return Response.json({ error: 'User not found' }, { status: 404 });
    }
    
    return Response.json({ ...data, _id: params.id });
  } catch (error) {
    return Response.json({ error: error.message }, { status: 500 });
  }
}

export async function DELETE(request, { params }) {
  try {
    const client = await clientPromise;
    const db = client.db('nextjs-tutorial');
    
    const result = await db.collection('users').deleteOne({
      _id: new ObjectId(params.id)
    });
    
    if (result.deletedCount === 0) {
      return Response.json({ error: 'User not found' }, { status: 404 });
    }
    
    return Response.json({ message: 'User deleted successfully' });
  } catch (error) {
    return Response.json({ error: error.message }, { status: 500 });
  }
}

通过本章的学习,你已经掌握了 Next.js API 路由的核心概念和使用方法。API 路由是 Next.js 的强大特性之一,它使得前后端开发可以在同一个项目中完成,大大简化了开发流程。在实际项目中,你可以根据具体需求创建各种 API 接口,与数据库进行交互,实现完整的业务逻辑。

© 2026 编程马·菜鸟教程 版权所有