Next.js API Routes:构建服务端功能

时间:2024-06-07 10:10:07

Next.js 的 API 路由允许你在 Next.js 应用程序中创建独立的服务端功能,这些功能可以处理 HTTP 请求并返回 JSON 数据或其他响应。API 路由位于项目中的 pages/api 目录下,每个文件都会映射到一个特定的 API 路径。

基本示例

pages/api/users.js

import type { NextApiRequest, NextApiResponse } from 'next';

// 获取用户列表
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method === 'GET') {
    const users = [
      { id: 1, name: 'User 1' },
      { id: 2, name: 'User 2' },
      { id: 3, name: 'User 3' },
    ];

    res.status(200).json(users);
  } else if (req.method === 'POST') {
    const user = req.body;

    // 假设这里有一个数据库连接
    // await addUserToDatabase(user);

    res.status(201).json({ message: 'User added successfully.' });
  } else {
    res.setHeader('Allow', ['GET', 'POST']);
    res.status(405).end(`Method ${req.method} Not Allowed`);
  }
}
  1. pages/api/users.js 文件定义了一个 API 路由,它将在 /api/users 路径上运行。
  2. handler 函数接收两个参数:req(NextApiRequest 对象,代表 HTTP 请求)和 res(NextApiResponse 对象,代表 HTTP 响应)。
  3. 当请求方法为 GET 时,函数返回用户列表(这里是一个硬编码的数组,实际应用中可能是从数据库查询)。
  4. 当请求方法为 POST 时,函数接收请求体中的用户数据,然后添加到数据库(这里只是模拟,实际应用中需要连接数据库)并返回成功消息。
  5. 如果请求方法不是 GET 或 POST,函数返回 405 方法不允许的错误。

Next.js API 路由默认处理 JSON 响应,但你也可以根据需要返回其他类型的内容。例如,如果你需要返回 HTML,可以使用 res.send 方法。

中间件与请求处理链

Next.js API 路由支持中间件模式,允许你在请求到达最终处理函数之前预处理请求或后处理响应。这可以用来验证请求头、鉴权、日志记录等。

Middleware 示例

假设我们想在所有 API 请求前验证一个 API 密钥:

// pages/api/middleware/authenticate.ts
export function authenticate(req: NextApiRequest, res: NextApiResponse, next: () => void) {
  const apiKey = req.headers['x-api-key'];
  
  if (!apiKey || apiKey !== process.env.API_KEY) {
    return res.status(401).json({ message: 'Unauthorized' });
  }
  
  next();
}

然后,在实际的 API 路由中使用此中间件:

// pages/api/users.js
import { authenticate } as middleware from './middleware/authenticate';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  authenticate(req, res, () => {
    // ...原有逻辑
  });
}

错误处理

良好的错误处理对于生产级应用至关重要。Next.js API 路由允许你自定义错误处理逻辑。

错误处理示例

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  try {
    // 假设这里可能会抛出错误
    const result = await fetchDataFromDatabase();

    res.status(200).json(result);
  } catch (error) {
    console.error('Error occurred:', error);
    res.status(500).json({ error: 'An error occurred while processing your request.' });
  }
}

类型安全

为了增强代码的健壮性和可维护性,利用 TypeScript 进行类型注解是个好习惯。

类型安全示例

// pages/api/users.ts
import type { NextApiRequest, NextApiResponse } from 'next';

type User = {
  id: number;
  name: string;
};

export default async function handler(req: NextApiRequest, res: NextApiResponse<User[] | { message: string }>) {
  // ...
}

与外部服务交互

大多数 API 路由会与外部服务交互,比如数据库、第三方 API 等。这里展示如何使用 axios 发起 HTTP 请求。

首先安装 axios

npm install axios

然后在 API 路由中使用:

import axios from 'axios';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  try {
    const response = await axios.get('https://api.example.com/data');
    res.status(200).json(response.data);
  } catch (error) {
    res.status(500).json({ error: 'Failed to fetch data from external service.' });
  }
}

定制路由与动态路由

Next.js API 路由不仅限于单一路径,还可以根据需要定制更复杂的路由结构,包括动态路由。

定制路由

如果你需要将多个相关的API端点组织在一起,可以创建子目录。例如,假设你正在构建一个博客API,你可以这样组织:

pages/
  api/
    blog/
      posts.ts          # 处理 /api/blog/posts 请求
      post/[id].ts       # 动态路由,处理 /api/blog/post/:id 请求
动态路由

动态路由允许你捕获URL中的一部分作为参数。在上面的例子中,[id] 是一个动态段,它会被实际的ID值替换。在处理函数中,你可以通过 req.query 访问这些动态参数。

动态路由示例 (pages/api/blog/post/[id].ts)
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  const { id } = req.query; // 获取动态ID

  if (!id) {
    return res.status(400).json({ message: 'Missing post ID' });
  }

  try {
    const post = await getPostById(id as string); // 假设这是从数据库获取文章的函数
    if (!post) {
      return res.status(404).json({ message: 'Post not found' });
    }
    return res.status(200).json(post);
  } catch (error) {
    console.error('Error fetching post:', error);
    return res.status(500).json({ message: 'Internal server error' });
  }

}

API 路由缓存

为了提升性能,你可能需要对API响应进行缓存。Next.js自身不直接提供API缓存机制,但你可以借助第三方库如 swr(用于客户端缓存)或在服务器端使用Redis等缓存服务。

服务器端缓存示例(使用 Redis)

首先,安装 redis 和 ioredis:
npm install redis ioredis
然后,在API路由中使用Redis缓存数据:
import redis from 'ioredis';

const redisClient = new redis(process.env.REDIS_URL);

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  const { id } = req.query;

  let post;
  try {
    // 尝试从Redis获取缓存
    post = await redisClient.get(`post:${id}`);
    if (post) {
      post = JSON.parse(post);
      return res.status(200).json(post);
    }
  } catch (err) {
    console.error('Redis error:', err);
  }

  // 缓存中没有数据,从数据库获取
  post = await getPostById(id as string);

  if (post) {
    // 存储到Redis以便下次使用
    redisClient.set(`post:${id}`, JSON.stringify(post));
    res.status(200).json(post);
  } else {
    res.status(404).json({ message: 'Post not found' });
  }
}

CORS 支持

跨源资源共享(CORS)是Web安全的重要方面,Next.js API路由默认支持CORS。你可以通过配置来进一步控制CORS策略:

import Cors from 'cors'; // 安装 cors 库

// 初始化 CORS 中间件
const cors = Cors({
  methods: ['GET', 'HEAD'],
});

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  // 使用 CORS 中间件
  await new Promise((resolve, reject) => {
    cors(req, res, (result) => {
      if (result instanceof Error) {
        reject(result);
      } else {
        resolve(result);
      }
    });
  });

  // .

…后续处理逻辑
}

2500G计算机入门到高级架构师开发资料超级大礼包免费送!