中文

学习如何利用 Next.js API 路由在您的 Next.js 应用中直接构建无服务器后端。本指南涵盖了从基本设置到处理身份验证、数据持久化等高级技术的所有内容。

Next.js API 路由:轻松构建您的后端

Next.js 以其强大的功能和直观的结构彻底改变了前端开发。但您知道它也能显著简化后端开发吗?Next.js API 路由允许您直接在 Next.js 应用中创建无服务器 API 端点,在许多情况下无需再使用独立的后端服务器。本综合指南将引导您完成使用 Next.js API 路由构建健壮且可扩展的后端的过程。

什么是 Next.js API 路由?

API 路由是您在 Next.js 项目的 /pages/api 目录中创建的无服务器函数。这些函数处理传入的 HTTP 请求并返回响应,就像传统的后端 API 一样。关键区别在于它们被部署为无服务器函数,这意味着您无需管理服务器或基础设施。

您可以将它们视为与您的 Next.js 前端无缝集成的轻量级、按需调用的后端函数。

使用 Next.js API 路由的好处

开始使用 Next.js API 路由

让我们创建一个返回 JSON 响应的简单 API 路由。首先,请确保您已设置好一个 Next.js 项目。如果还没有,请使用以下命令创建一个:

npx create-next-app my-app
cd my-app

现在,在 /pages/api 目录下创建一个名为 hello.js 的文件:

// pages/api/hello.js
export default function handler(req, res) {
  res.status(200).json({ name: 'John Doe' })
}

此代码定义了一个简单的 API 路由,它会响应一个包含姓名“John Doe”的 JSON 对象。要访问此 API 路由,请启动您的 Next.js 开发服务器:

npm run dev

然后,打开您的浏览器并访问 http://localhost:3000/api/hello。您应该会看到以下 JSON 响应:

{"name": "John Doe"}

理解 API 路由处理器

API 路由中的 handler 函数接收两个参数:

您可以使用这些对象来处理不同类型的请求、从请求体中读取数据、设置响应头以及发送不同类型的响应。

处理不同的 HTTP 方法

您可以使用 req.method 属性来确定传入请求的 HTTP 方法,并相应地处理不同的方法。例如:

// pages/api/method.js
export default function handler(req, res) {
  if (req.method === 'GET') {
    // 处理 GET 请求
    res.status(200).json({ message: 'This is a GET request' })
  } else if (req.method === 'POST') {
    // 处理 POST 请求
    res.status(200).json({ message: 'This is a POST request' })
  } else {
    // 处理其他方法
    res.status(405).json({ message: 'Method Not Allowed' })
  }
}

在此示例中,API 路由处理 GET 和 POST 请求。如果请求方法是 GET,它会响应一个包含消息“This is a GET request”的 JSON 对象。如果请求方法是 POST,它会响应一个包含消息“This is a POST request”的 JSON 对象。如果请求方法是其他任何方法,它会响应一个 405 Method Not Allowed 错误。

从请求体中读取数据

对于 POST、PUT 和 PATCH 请求,您通常需要从请求体中读取数据。Next.js 提供了对解析 JSON 和 URL 编码的请求体的内置支持。要解析 JSON 请求体,您可以使用 req.body 属性。例如:

// pages/api/post.js
export default async function handler(req, res) {
  if (req.method === 'POST') {
    const { name, email } = req.body

    // 处理数据
    console.log('Name:', name)
    console.log('Email:', email)

    res.status(200).json({ message: 'Data received successfully' })
  } else {
    res.status(405).json({ message: 'Method Not Allowed' })
  }
}

要测试此 API 路由,您可以使用 Postman 或 curl 等工具发送带有 JSON 主体的 POST 请求:

curl -X POST -H "Content-Type: application/json" -d '{"name": "Jane Doe", "email": "jane.doe@example.com"}' http://localhost:3000/api/post

设置响应头

您可以使用 res.setHeader() 方法来设置响应头。这对于设置内容类型、缓存控制和其他重要信息很有用。例如:

// pages/api/headers.js
export default function handler(req, res) {
  res.setHeader('Content-Type', 'application/json')
  res.setHeader('Cache-Control', 's-maxage=3600')
  res.status(200).json({ message: 'Hello, world!' })
}

在此示例中,API 路由将 Content-Type 头设置为 application/json,表示响应是一个 JSON 对象。它还将 Cache-Control 头设置为 s-maxage=3600,这会告诉浏览器和 CDN 将响应缓存长达 1 小时。

错误处理

在您的 API 路由中优雅地处理错误非常重要。您可以使用 try-catch 块来捕获异常并向客户端发送适当的错误响应。例如:

// pages/api/error.js
export default async function handler(req, res) {
  try {
    // 模拟一个错误
    throw new Error('Something went wrong')
  } catch (error) {
    console.error(error)
    res.status(500).json({ message: 'Internal Server Error' })
  }
}

在此示例中,API 路由通过抛出一个新的 Error 对象来模拟错误。catch 块捕获错误,将其记录到控制台,并向客户端发送 500 Internal Server Error 响应。在生产环境中,请考虑使用像 Sentry 或 Datadog 这样强大的日志记录系统。

连接到数据库

API 路由最常见的用例之一是连接到数据库。Next.js API 路由可与各种数据库无缝集成,包括:

以下是在 Next.js API 路由中如何连接到 MongoDB 数据库的示例:

// pages/api/mongodb.js
import { MongoClient } from 'mongodb'

const uri = process.env.MONGODB_URI
const options = {}

let client
let clientPromise

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

if (process.env.NODE_ENV === 'development') {
  // 在开发模式下,使用一个全局变量,以便在 HMR (热模块替换)
  // 引起的模块重新加载之间保留该值。
  if (!global._mongoClientPromise) {
    client = new MongoClient(uri, options)
    global._mongoClientPromise = client.connect()
  }
  clientPromise = global._mongoClientPromise
} else {
  // 在生产模式下,最好不要使用全局变量。
  client = new MongoClient(uri, options)
  clientPromise = client.connect()
}

// 导出一个模块作用域的 MongoClient promise。通过在单独的模块中执行此操作,
// 可以在多个函数之间安全地重用客户端。
// 参见:https://github.com/vercel/next.js/blob/canary/examples/with-mongodb/lib/mongodb.js
export default async function handler(req, res) {
  try {
    const client = await clientPromise
    const db = client.db(process.env.MONGODB_DB)
    const collection = db.collection('users')

    const users = await collection.find({}).toArray()

    res.status(200).json({ users })
  } catch (e) {
    console.error(e)
    res.status(500).json({ message: 'Failed to fetch users' })
  }
}

在运行此代码之前,请确保您已安装 mongodb 包:

npm install mongodb

您还需要设置 MONGODB_URIMONGODB_DB 环境变量。这些变量应在您的 .env.local 文件中(或在您的托管提供商的环境变量设置中用于生产环境)定义。MONGODB_URI 包含到您的 MongoDB 数据库的连接字符串,而 MONGODB_DB 指定数据库名称。

身份验证与授权

保护您的 API 路由对于安全至关重要。可以使用各种身份验证和授权技术来保护 Next.js API 路由,包括:

以下是使用 JWT 身份验证保护 API 路由的示例:

// pages/api/protected.js
import jwt from 'jsonwebtoken'

const secret = process.env.JWT_SECRET

export default function handler(req, res) {
  const token = req.headers.authorization?.split(' ')[1]

  if (!token) {
    return res.status(401).json({ message: 'Unauthorized' })
  }

  try {
    const decoded = jwt.verify(token, secret)
    // “decoded”对象包含嵌入在令牌中的用户信息
    // 例如:const userId = decoded.userId;

    // 继续处理请求
    res.status(200).json({ message: 'Protected resource accessed successfully' })
  } catch (error) {
    return res.status(401).json({ message: 'Invalid token' })
  }
}

在运行此代码之前,请确保您已安装 jsonwebtoken 包:

npm install jsonwebtoken

您还需要设置 JWT_SECRET 环境变量。这应该是一个强壮的、随机生成的密钥,用于签署和验证 JWT。请安全地存储此密钥,切勿在您的客户端代码中暴露它。

中间件

虽然 Next.js 没有像 Express.js 那样为 API 路由提供传统的中间件,但您可以通过用可重用函数包装 API 路由处理器来实现类似的功能。这使您可以执行以下任务:

以下是如何创建一个简单的日志记录中间件的示例:

// utils/middleware.js
export function withLogging(handler) {
  return async function(req, res) {
    console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`)
    return handler(req, res)
  }
}

要使用此中间件,只需用 withLogging 函数包装您的 API 路由处理器:

// pages/api/logged.js
import { withLogging } from '../../utils/middleware'

async function handler(req, res) {
  res.status(200).json({ message: 'This request was logged' })
}

export default withLogging(handler)

构建 Next.js API 路由的最佳实践

高级技术

后台任务

对于不应阻塞 API 响应的长时间运行的任务,请考虑使用后台任务。您可以使用像 BullMQ 或 Bree 这样的库来管理您的后台任务并异步处理它们。

WebSockets

对于实时应用,您可以在 Next.js API 路由中使用 WebSockets。像 Socket.IO 和 ws 这样的库可以轻松地在客户端和服务器之间建立持久连接。

GraphQL

如果您需要一种更灵活、更高效的方式来获取数据,请考虑使用 GraphQL。您可以使用像 Apollo Server 或 Yoga 这样的库在您的 Next.js 应用中创建 GraphQL API 端点。

结论

Next.js API 路由提供了一种强大而便捷的方式,可以直接在您的 Next.js 应用中构建无服务器后端。通过利用无服务器架构的优势,您可以简化开发、提高性能并降低成本。无论您是构建一个简单的联系表单还是一个复杂的电子商务平台,Next.js API 路由都可以帮助您轻松创建健壮且可扩展的后端。通过对基础知识的扎实理解和最佳实践的应用,您可以利用这个强大的工具来创建高效、安全且可全球访问的应用。