#18不要使用 Next.js 作为主服务器!✅ 这就是我切换到自定义服务器的原因!🤯

在不断发展的 Web 开发世界中,构建可扩展、高效且可维护的应用程序至关重要。虽然 Next.js 是一个用于创建无缝全栈应用程序的强大框架,但仅依靠其内置服务器来处理复杂的工作流程有时会带来挑战。在这篇博客中,我将分享我在宠物爱好者社交媒体平台上工作的经验,在那里我意识到分离 Next.js 前端和后端操作的重要性。

使用 Next.js 作为服务器的挑战

1. 长时间运行的任务

Next.js 服务器(尤其是部署在 Vercel 等平台上时)的执行时间存在限制。例如:

  • 免费计划:任务必须在 10 秒内完成。
  • 付费计划:最长时间延长至5-9分钟。
  • limitations on execution

    这一限制使得 Next.js 不适合长时间运行的操作,例如**文本转视频生成**等基于 AI 的工作流,这些工作流占用大量资源,需要更长的执行时间。AI 应用程序正在迅速发展,这些限制可能会阻碍它们在 Next.js 服务器上的实现。

    2. 后台任务、作业队列和 Cron 作业

    处理后台任务或设置作业队列是另一个痛点。在使用 **RabbitMQ** 时,我意识到依赖 Next.js 进行此类工作流的局限性。这些限制可能会导致处理需要异步执行的任务效率低下,例如:

  • 批量发送电子邮件。
  • 处理大型数据集。
  • 使用 cron 作业安排定期任务。
  • 这对我来说是一个重要的学习曲线,因为我最初选择 Next.js 进行这些操作,但后来遇到了问题。

    3.数据库连接管理

    Next.js 的无服务器架构会针对每个请求启动和关闭实例,这可能会导致频繁的数据库连接。这会导致:

  • 连接开销:增加延迟和潜在的连接池耗尽。
  • 工作流程效率低下:数据库使用量大的应用程序受到的影响最大。
  • 4.冷启动延迟

    Next.js 中的无服务器函数经常会遇到**冷启动**,尤其是在一段时间未调用该函数的情况下。这可能导致:

  • 用户响应时间变慢。
  • 关键 API 端点的性能不佳。
  • 5. 没有持久文件系统

    Next.js 的无服务器特性意味着它没有持久文件系统。这使得以下操作变得具有挑战性:

  • 存储临时文件。
  • 有效地处理和存储上传的媒体。
  • 6. WebSocket 限制

    由于连接时间有限,基于 WebSocket 的应用程序(例如实时聊天或实时更新)在使用 Next.js 时会面临挑战。持久连接难以维持,这使得 Next.js 不太适合 WebSocket 密集型应用程序。

    7. 微服务和可扩展性

    Next.js 服务器本身并不是为复杂的微服务架构而设计的。虽然它们擅长提供高级组件和功能,但它们缺乏以下所需的自定义选项:

  • 隔离单个服务中的故障。
  • 独立于前端扩展后端服务。
  • 为什么定制服务器是更好的选择

    经过多次尝试和错误,我发现了为后端操作创建自定义 Node.js 服务器的好处。原因如下:

    1. 最适合工作的工具

    使用自定义服务器,您可以选择适合您特定需求的工具。无论是 **Express.js**、**Koa** 还是 **Fastify**,您都可以完全控制后端堆栈。

    2. 独立扩展

    后端团队可以根据流量或工作负载独立扩展服务器。这种分离允许:

  • 高效的资源配置。
  • 高负载下性能更佳。
  • 3.故障隔离

    自定义服务器使您能够隔离特定微服务内的故障,防止问题蔓延至整个应用程序。

    最佳解决方案:将 Next.js 与自定义服务器相结合

    对于 **Petreon**,最好的方法是利用 Next.js 进行前端操作,并使用自定义服务器进行后端操作。这种混合模型让我能够利用两个系统的优势,同时解决它们的局限性。

    架构概述

    该架构的结构如下:

  • Next.js 客户端:处理用户界面并与后端通信。
  • Next.js Server:用于身份验证和其他与用户管理相关的轻量级操作。
  • 自定义服务器:管理繁重的后端操作,如数据库交互、长时间运行的任务、WebSockets 等。
  • arc

    与 Kinde 一起实施

    Kinde 是在此设置中管理身份验证的绝佳平台。您可以按照以下方法集成它:

    Next.js 服务器(身份验证)

    const { jwtVerify } = require("@kinde-oss/kinde-node-express");
    
    const jwtVerifier = jwtVerify("https://yourdomain.kinde.com", {
      audience: "",
    });
    
    app.use(async (req, res, next) => {
      try {
        await jwtVerifier(req, res, next);
      } catch (err) {
        console.error("Token validation failed:", err.message);
        res.status(401).send("Unauthorized");
      }
    });

    自定义服务器

    在后端(自定义服务器)中,设置受保护的路由来处理安全操作。

    app.get("/api/protected", jwtVerifier, (req, res) => {
      res.json({ message: "This is protected data" });
    });

    Next.js 客户端

    使用 Kinde 客户端库来获取令牌并与后端通信。

    import { useKindeBrowserClient } from "@kinde-oss/kinde-auth-nextjs";
    import { useEffect } from "react";
    
    export default function DashboardPage() {
      const { accessTokenRaw } = useKindeBrowserClient();
    
      useEffect(() => {
        if (!accessTokenRaw) return;
    
        const fetchData = async () => {
          const response = await fetch("http://localhost:5000/api/protected", {
            headers: {
              Authorization: `Bearer ${accessTokenRaw}`,
            },
          });
          const data = await response.json();
          console.log(data);
        };
    
        fetchData();
      }, [accessTokenRaw]);
    
      return (
        

    Welcome to the Dashboard

    ); }

    完成所有设置后,我使用 Postman 和真实用户登录验证了 AP​​I 功能。一切都按预期进行,文档在整个过程中都发挥了重要作用。

    结论

    将后端服务器与 Next.js 分离是一项战略决策,可增强可扩展性、故障隔离和整体性能。对于 AI 工作流、WebSocket 和数据库密集型操作至关重要的应用程序,这种方法提供了成功所需的灵活性和能力。

    通过将 Next.js 的前端功能与自定义服务器相结合,您可以构建高效且可扩展的应用程序。首先使用 **Kinde** 等平台进行身份验证,然后无缝连接前端和后端以获得最佳效果。

    构建现代 Web 应用程序的关键在于做出正确的架构选择——这种方法可确保您已准备好应对遇到的任何挑战!