你好呀! 如果您和我一样,您可能会对当今实时 Web 应用程序的无缝交互性感到惊叹——那些即时响应的聊天机器人、无需刷新页面即可弹出的实时通知,以及无需刷新即可更新的协作工具。眨眼间。在数字时代,实时功能不再是一种奢侈,而是一种期望。 现在,如果您一直在跟踪 Next.js 领域的发展,您可能已经听说过 13.4 版本中值得关注的功能,尤其是游戏规则改变者:服务器操作。您是否好奇这将如何重新定义我们打造实时体验的方式? 嗯,我也是! 和我一起深入研究这个案例研究,我们将踏上利用 服务器操作的强大功能和技巧构建实时应用程序的旅程。无论您是经验丰富的开发人员还是刚刚涉足实时应用程序领域,都有大量的见解等着您。 Next.js 让我们开始吧,好吗? 目录 背景:了解实时应用程序 Next.js 13.4 的新增功能:服务器操作概览 奠定基础:我们的实时项目范围 入门:初始设置 构建后端:利用服务器操作 设计前端:无缝的用户体验 测试实时能力 增强和优化 结论与未来展望 资源和进一步阅读 1. 背景:了解实时应用程序 在当今快节奏的数字环境中,“实时”一词经常出现在从游戏和金融到通信和社交媒体的各种环境中。但在 Web 应用程序世界中“实时”到底意味着什么? L 让我们揭开这一点。 什么是实时应用程序? 实时应用程序是立即响应用户输入或外部事件的系统或程序,提供即时反馈,没有明显的延迟。简而言之,将它们视为“实时”发展的实时动态平台,反映了现代数字生态系统中不断流动的信息。 现实生活中的例子 为了正确理解这一点,请考虑一些普遍存在的例子: : 和 Telegram 等平台可以毫不延迟地发送、接收和查看消息。 即时通讯应用程序 WhatsApp :想想 Google Docs,多个用户可以同时编辑文档,实时观察彼此的更改。 协作工具 :显示随市场波动即时更新的股票价格的平台。 实时股票代码 :玩家之间和环境之间的交互零延迟,确保无缝的游戏体验。 在线多人游戏 实时应用程序的相关性 那么,为什么实时功能如此受追捧呢? :现代用户期望即时性。无论是聊天应用程序还是天气更新,任何明显的延迟都可能导致用户满意度下降。 用户期望 :实时功能可实现更具交互性和沉浸式的用户体验,从而提高用户参与度。 增强的交互性 :提供实时功能可以使平台在拥挤的市场中脱颖而出,提供吸引和留住用户的独特卖点。 竞争优势 未来的挑战 构建实时应用程序并非没有障碍: :实时应用程序通常需要处理大量并发连接,需要强大的基础设施。 可扩展性问题 :确保实时数据在各种用户界面之间保持一致可能是一个挑战,特别是在多个同时编辑或交互的情况下。 数据完整性 :实时应用程序的好坏取决于其最慢的组件。确保最小的延迟需要仔细优化和有效利用资源。 延迟 现在我们已经对实时应用程序有了基本的了解,我们将深入研究 Next.js 13.4 及其服务器操作如何成为渴望打造这种沉浸式体验的开发人员的关键工具。 2. Next.js 13.4 中的新增功能:服务器操作概览 在不断发展的 Web 开发领域,Next.js 始终走在最前沿,推出的功能重新定义了我们构建应用程序的方式。版本 13.4 也不例外,特别是它强调服务器操作。但在我们深入研究之前,让我们先澄清一些术语: 行动入门 React 生态系统中 虽然仍处于实验阶段,但通过允许开发人员执行异步代码来响应用户交互,已经带来了范式转变。 的操作 有趣的是,虽然它们并不是 Next.js 或 Server Components 所独有的,但通过 Next.js 使用它们意味着您处于 React 实验通道中。 React 对于熟悉 HTML 表单的人来说,您可能还记得将 URL 传递给 属性。现在,通过 Actions,您可以直接传递函数,使交互更加动态和集成。 action <button action={() => { /* async function logic here */ }}>Click me!</button> React 与 Actions 的集成还为乐观更新提供了内置解决方案。这强调了虽然操作是开创性的,但模式仍在不断发展,并且可能会添加更新的 API 以进一步丰富它们。 拥抱表单操作 代表了 React 操作与标准 API 的巧妙结合。它们与 HTML 中的原始 属性产生共鸣,使开发人员能够增强渐进式加载状态和其他开箱即用的功能。 表单操作 <form> formaction <!-- Traditional HTML approach --> <form action="/submit-url"> <!-- form elements --> </form> <!-- With Next.js 13.4 Form Actions --> <form action={asyncFunctionForSubmission}> <!-- form elements --> </form> 服务器功能和服务器操作 本质上是在服务器端运行但可以从客户端调用的函数。这些将 Next.js 的服务器端渲染能力提升到一个全新的水平。 服务器函数 过渡到 ,它们可以理解为服务器功能,但专门作为操作触发。它们与表单元素的集成,尤其是通过 属性,确保表单即使在客户端 JavaScript 加载之前也保持交互性。这意味着更流畅的用户体验,React 水合不是表单提交的先决条件。 服务器操作 action // A simple Server Action in Next.js 13.4 <form action={serverActionFunction}> <!-- form elements --> </form> 了解服务器突变 最后,我们有 ,它是服务器操作的子集。当您需要修改服务器上的数据然后执行特定响应(例如 、 或 )时,这些功能特别强大。 服务器突变 redirect revalidatePath revalidateTag const serverMutationFunction = async () => { // Modify data logic here... // ... return { revalidatePath: '/updated-path' }; } <form action={serverMutationFunction}> <!-- form elements --> </form> 总而言之,Next.js 13.4 的服务器操作框架以操作、表单操作、服务器功能和服务器突变为基础,体现了实时 Web 应用程序的变革性方法。 注释: 当我们继续进行案例研究时,您将亲眼目睹这些功能所带来的强大功能。 那么,让我们为即将到来的激动人心的旅程做好准备吧! 3. 做好准备:我们的实时项目范围 在构建实时应用程序的背景下,Next.js 13.4 的服务器操作发挥着至关重要的作用。这些 alpha 功能可以轻松管理服务器端数据突变、减少客户端 JavaScript 并逐步增强表单。 启用服务器操作 首先,您需要在 Next.js 项目中启用服务器操作。只需将以下代码添加到您的 文件中: next.config.js module.exports = { experimental: { serverActions: true, }, } 创建与调用 服务器操作可以在使用它的服务器组件中定义,也可以在单独的文件中定义,以便在客户端和服务器组件之间重用。 以下是创建和调用服务器操作的方法: :可以在服务器组件内轻松定义服务器操作,如下所示: 在服务器组件内 export default function ServerComponent() { async function myAction() { 'use server' // ... } } :在客户端组件内使用服务器操作时,在单独的文件中创建操作,然后导入它。 使用客户端组件 // app/actions.js 'use server' export async function myAction() { // ... } 在客户端组件中导入并使用: // app/client-component.js import { myAction } from './actions' export default function ClientComponent() { return ( <form action={myAction}> <button type="submit">Add to Cart</button> </form> ) } :您可以使用 等自定义方法来调用表单、按钮或输入之外的服务器操作。 自定义调用 startTransition // Example using startTransition 'use client' import { useTransition } from 'react' import { addItem } from '../actions' function ExampleClientComponent({ id }) { let [isPending, startTransition] = useTransition() return ( <button onClick={() => startTransition(() => addItem(id))}> Add To Cart </button> ) } 渐进增强 Next.js 13.4 还提供渐进式增强功能,允许 在没有 JavaScript 的情况下运行。服务器操作可以直接传递到 ,即使 JavaScript 被禁用,也使表单具有交互性。 <form> <form> // app/components/example-client-component.js 'use client' import { handleSubmit } from './actions.js' export default function ExampleClientComponent({ myAction }) { return ( <form action={handleSubmit}> {/* ... */} </form> ) } 尺寸限制 默认情况下,发送到服务器操作的最大请求正文为 1MB。如果需要,您可以使用 选项配置此限制: serverActionsBodySizeLimit module.exports = { experimental: { serverActions: true, serverActionsBodySizeLimit: '2mb', }, } 4. 开始使用:初始设置 创建新的 Next.js 13.4 项目 要开始使用 Next.js 13.4 构建实时应用程序,第一步是创建一个新项目。您可以使用标准 Next.js CLI 命令来初始化您的项目: npx create-next-app@latest my-real-time-app 将 替换为您的项目所需的名称。此命令使用默认配置设置一个新的 Next.js 项目。 my-real-time-app 实时功能所需的依赖项和包 对于实时功能,您可能需要某些包和依赖项。根据应用程序的具体情况,这些范围可能从 WebSockets 库到 GraphQL 订阅等等。 确保您已查看项目要求并添加了必要的依赖项。 然而,随着 Next.js 13.4 对服务器操作的支持,已经有一个支持服务器端处理的内置设置,这可以帮助实现一些实时功能。 项目结构和目录设置的简要概述 应用程序路由器 随着 Next.js 13.4 的推出, 成为一项重要功能,允许开发人员利用共享布局、嵌套路由、错误处理等。它被设计为与现有的 目录结合使用,但它位于一个名为 的新目录中。 App Router pages app 要开始使用 App Router: 在项目的根目录中创建一个 目录。 app 在此目录中添加您的路由或组件。 默认情况下, 目录中的组件是 ,提供最佳性能并允许开发人员轻松采用它们。 app Server Components 这是一个示例结构: my-real-time-app/ │ ├── app/ # Main directory for App Router components │ ├── _error.js # Custom error page │ ├── _layout.js # Shared layout for the app │ │ │ ├── dashboard/ # Nested route example │ │ ├── index.js # Dashboard main view │ │ └── settings.js # Dashboard settings view │ │ │ ├── index.js # Landing/Home page │ ├── profile.js # User profile page │ ├── login.js # Login page │ └── register.js # Registration page │ ├── public/ # Static assets go here (images, fonts, etc.) │ ├── images/ │ └── favicon.ico │ ├── styles/ # Global styles or variables │ └── global.css │ ├── package.json # Dependencies and scripts ├── next.config.js # Next.js configuration └── README.md # Project documentation 服务器组件与客户端组件 考虑组件如何呈现至关重要。在传统的 SPA(单页应用程序)中,React 在客户端呈现整个应用程序。使用服务器组件,大部分应用程序都在服务器上呈现,从而带来性能优势。这是一个指南: :非常适合应用程序的非交互式部分。这些组件在服务器上呈现并以 HTML 形式发送到客户端。这里的优点是提高了性能,减少了客户端 JavaScript,以及直接获取数据或访问后端资源的能力。 服务器组件 :用于交互式 UI 元素。它们在服务器上预渲染,然后在客户端上“水合”以添加交互性。 客户端组件 为了区分这些组件,Next.js 引入了 指令。该指令指示组件应被视为客户端组件。它应该放在组件文件的顶部,在任何导入之前。 "use client" 例如,如果您有一个交互式计数器(如提供的代码中所示),您将使用 指令来指示它是客户端组件。 "use client" 建议 在构建您的应用程序时,请遵循以下一些准则: 默认情况下使用 (因为它们位于 目录中)。 服务器组件 app 仅当您有特定的用例(例如添加交互性、利用仅限浏览器的 API 或利用依赖于状态或浏览器功能的 React 挂钩)时才选择 。 客户端组件 按照此结构和设置,您将能够很好地使用 Next.js 13.4 的服务器操作构建高性能的实时应用程序。 注意: 5. 构建后端:利用服务器操作 当将实时后端功能集成到我们的项目中时,Next.js 13.4 的力量大放异彩。让我们使用 的相关代码示例来逐步完成这些步骤。 my-real-time-app 介绍如何在该项目中使用服务器操作 对于我们的 ,服务器操作充当 和 之间的主要桥梁,允许高效的数据交易,而不需要单独的 API。 my-real-time-app 前端 后端 // my-real-time-app/app/actions/index.js export * from './auth-action'; export * from './chat-action'; 设置用于处理用户身份验证的服务器操作 在 中,我们利用服务器操作来简化身份验证过程。 my-real-time-app // my-real-time-app/app/actions/auth-action.js export const login = async (credentials) => { // Logic for authenticating user with credentials // Return user details or error message }; export const logout = async (userId) => { // Logic for logging out the user // Return success or error message }; export const register = async (userInfo) => { // Logic for registering a new user // Store user in database and return success or error message }; 创建用于发送和接收实时消息的服务器操作 对于聊天功能: // my-real-time-app/app/actions/chat-action.js export const sendMessage = async (messageDetails) => { // Logic to send a new message // Store message in database and inform other users via WebSocket or similar }; export const receiveMessage = async () => { // Logic to receive a message in real-time // Return the message details }; export const getRecentMessages = async (userId) => { // Logic to fetch recent messages for the user // Retrieve messages from the database }; 集成数据库(例如 MongoDB)以实现消息持久化 使用 MongoDB 作为我们的主要数据存储: // Initialize MongoDB connection const { MongoClient } = require('mongodb'); const client = new MongoClient(process.env.MONGODB_URI); await client.connect(); // Now, use this connection in server actions to interact with the database. 在我们的聊天操作中: // my-real-time-app/app/actions/chat-action.js export const sendMessage = async (messageDetails) => { const messagesCollection = client.db('chatDB').collection('messages'); await messagesCollection.insertOne(messageDetails); // Inform other users via WebSocket or similar }; 通过服务器操作确保安全、快速的通信 为了安全: // Middleware for validating request data const validateRequest = (req) => { // Validation logic here return isValid; }; export const sendMessage = async (messageDetails) => { if (!validateRequest(messageDetails)) { throw new Error("Invalid request data"); } // Remaining logic... }; 6. 设计前端:无缝的用户体验 在本节中,我们将为 构建一个直观且响应灵敏的聊天界面。 Next.js 13.4 的服务器组件的集成将实现实时更新,带来流畅的用户体验。 my-real-time-app 构建主聊天界面 首先,我们来创建主聊天界面: // my-real-time-app/app/chat-interface.js import { useEffect, useState } from 'react'; import { getRecentMessages } from './actions/chat-action'; export default function ChatInterface() { const [messages, setMessages] = useState([]); useEffect(() => { async function loadMessages() { const recentMessages = await getRecentMessages(); setMessages(recentMessages); } loadMessages(); }, []); return ( <div className="chatBox"> {messages.map(msg => ( <p key={msg.id}>{msg.content}</p> ))} </div> ); } 该组件在加载时获取最近的消息并将其呈现在聊天框中。 将前端连接到服务器操作以进行实时更新 现在,我们将使用 WebSocket 的基本示例来设置实时更新: // my-real-time-app/app/chat-interface.js const [socket, setSocket] = useState(null); useEffect(() => { const ws = new WebSocket("ws://your-backend-url/ws"); ws.onmessage = (event) => { const newMessage = JSON.parse(event.data); setMessages(prevMessages => [...prevMessages, newMessage]); }; setSocket(ws); return () => { ws.close(); }; }, []); 该挂钩建立 WebSocket 连接并在收到新消息时更新消息列表。 实施新消息通知 为了获得更好的用户体验,让我们通知用户新消息: // my-real-time-app/app/chat-interface.js useEffect(() => { if (messages.length && "Notification" in window && Notification.permission === "granted") { const lastMessage = messages[messages.length - 1]; new Notification(`New message from ${lastMessage.sender}: ${lastMessage.content}`); } }, [messages]); 每次消息列表更新为新消息时,此效果都会发送浏览器通知。 确保流畅、无延迟的用户交互的技术 为了确保流畅的体验: 延迟加载重型组件: const HeavyComponent = React.lazy(() => import('./HeavyComponent')); function Chat() { return ( <React.Suspense fallback={<div>Loading...</div>}> <HeavyComponent /> </React.Suspense> ); } 使用 Next.js 的 来拆分逻辑: React Server Components 请记住,从早期的文档来看,服务器组件可用于非交互部分,而客户端组件可以处理交互部分,从而减少发送到客户端的 JavaScript 量。 例如,在我们的聊天中,消息历史记录可以是服务器组件,而需要客户端交互的输入字段和发送按钮可以是客户端组件。 7. 测试实时能力 随着我们的实时应用程序的核心组件就位,必须确保它们按预期运行,并且具有高性能、可扩展性和健壮性。本节阐述了为实时系统(例如我们的 量身定制的各种测试方法。 my-real-time-app 测试实时功能的工具和策略 使用 Cypress 进行端到端测试 对于实时应用程序,端到端测试至关重要。让我们用 Cypress 设置一个示例: // cypress/integration/chat.spec.js describe('Chat functionality', () => { it('should send and receive messages in real-time', () => { cy.visit('/chat'); cy.get('[data-cy=messageInput]').type('Hello, World!'); cy.get('[data-cy=sendButton]').click(); cy.contains('Hello, World!').should('exist'); }); }); 用火炮进行负载测试 这将有助于理解系统在大量用户或消息下的行为方式: # artillery-config.yml config: target: 'http://my-real-time-app.com' phases: - duration: 300 arrivalRate: 20 scenarios: - flow: - emit: channel: 'chat' payload: message: 'Hello, World!' $ artillery run artillery-config.yml 解决潜在的瓶颈和性能问题 分析服务器性能 Node.js 提供用于分析的内置工具,并且 标志可以与 Next.js 开发服务器一起使用来启用 Node.js 检查器。通过使用 Chrome 的 DevTools,人们可以深入了解性能瓶颈。 --inspect 客户端性能分析 对于客户端,Chrome DevTools 中的 选项卡等工具可以帮助识别渲染瓶颈。尤其是在实时更新的情况下,确保不会发生不必要的渲染。 Performance 确保实时应用程序的可扩展性和稳健性 使用 SWR 或 React Query 进行状态管理 实时应用程序通常涉及保持客户端状态与服务器同步。 SWR 或 React Query 等库通过提供自动重新获取、缓存和实时同步等功能来帮助简化这一过程。 SWR 示例: // my-real-time-app/app/chat-interface.js import useSWR from 'swr'; function ChatInterface() { const { data: messages } = useSWR('/api/messages', fetcher); // ... rest of the component } 水平缩放 对于后端可扩展性,尤其是 WebSocket,请考虑使用 Redis 等解决方案来管理服务器多个实例的状态。这样,如果一个服务器实例收到一条消息,它可以将其广播到连接到其他服务器实例的客户端。 数据库优化 确保您的数据库查询(尤其是那些在实时应用程序中频繁运行的查询)得到优化。对重要列建立索引,并考虑对经常访问的数据使用数据库缓存解决方案。 测试实时应用程序需要结合标准软件测试技术和一些专门针对实时系统的挑战和特性而定制的技术。确保对 严格的测试制度,无论用户流量或数据流的规模如何,我们都可以保证流畅且响应迅速的用户体验。 注意: my-real-time-app 10. 增强和优化 随着我们的实时应用程序的基础架构稳固到位,我们的注意力现在转向完善其功能和性能。以下是一些增强用户体验和优化 策略: my-real-time-app 增强用户体验的技巧 实施已读回执 当收件人阅读了用户的消息后,向用户提供视觉反馈。这增强了实时聊天的交互性。 // my-real-time-app/app/components/Message.js function Message({ content, status }) { return ( <div> <p>{content}</p> {status === 'read' && <span>✓ Read</span>} </div> ); } 显示在线状态 当用户在线时,在用户名或头像旁边显示一个指示符。 // my-real-time-app/app/components/UserStatus.js function UserStatus({ isOnline }) { return ( <div> {isOnline ? <span className="online-indicator"></span> : <span className="offline-indicator"></span>} </div> ); } 优化服务器操作以减少延迟 服务器端批处理 在可行的情况下批量进行服务器端更新,以减少发送到客户端的消息数量。 压缩 WebSocket 消息 对于更新频率较高的应用程序,可以考虑压缩 WebSocket 消息以减少传输的数据量并提高速度。 // Example: Setting up compression with a WebSocket server const WebSocket = require('ws'); const wss = new WebSocket.Server({ perMessageDeflate: { zlibDeflateOptions: { // Add compression options here } } }); 去抖频繁更新 如果您注意到客户端的快速连续更新,请考虑消除这些更新,将它们合并为更少、更有意义的更新。 确保数据完整性和容错能力 事件溯源 对于应用程序中数据完整性至关重要的关键部分,请考虑采用事件溯源模式。这可确保应用程序状态的每次更改都被捕获为一个事件,从而实现事件的可靠恢复和重放。 实施重试逻辑 确保如果由于网络问题导致消息发送失败或更新未完成,则有重试机制。 // Example: Simple retry logic with fetch let retries = 3; function fetchData(url) { fetch(url) .then(response => response.json()) .catch(error => { if (retries > 0) { retries--; fetchData(url); } else { console.error('Failed to fetch data after 3 retries'); } }); } 备份和恢复计划 定期备份数据并确保您有清晰的计划和流程来在发生故障时恢复数据。使用数据库复制或 Cassandra 等分布式数据库来实现容错。 的持续成功不仅取决于其核心功能,还取决于确保流畅的用户体验的细微增强和持续优化。通过结合上面列出的策略,我们准备为用户提供可靠且令人愉悦的卓越聊天体验。 注: my-real-time-app 11. 结论与未来展望 回顾构建实时应用程序的旅程 我们的 之旅从 Next.js 13.4 的初始设置开始,一直到使用服务器操作构建后端、设计无缝的前端体验,并确保实时功能经过测试和优化。我们深入研究了服务器和客户端组件的细微差别,确保服务器端渲染和客户端交互之间的有效平衡。 my-real-time-app Next.js 13.4 的服务器操作对项目的影响和重要性 Next.js 13.4 中服务器操作的引入彻底改变了我们处理实时应用程序的方法。它使我们能够构建一个高度交互式的聊天应用程序,利用服务器和客户端渲染的优势。这不仅优化了性能,而且还促进了无缝用户交互,而不会影响安全性或效率。 未来可以添加到应用程序的增强功能和功能 虽然 已经取得了长足的进步,但未来增强的潜力仍然巨大: my-real-time-app :引入实时视频聊天功能。 视频聊天集成 :允许用户创建、加入或离开群聊。 群聊 :通过加密消息来提高安全性,以便只有发送者和接收者可以解密它们。 端到端加密 :让用户可以选择通过头像、状态消息和主题来个性化他们的个人资料。 可定制的用户个人资料 :实施人工智能驱动的聊天机器人以进行自动响应。 聊天机器人 12. 资源和进一步阅读 当您踏上实时应用程序之旅并深入了解 Next.js 的功能和复杂性时,这里有一个精选的资源列表,可以为您提供指导、启发和进一步教育: 官方文档 :有关此版本中所有新增内容和改进内容的综合指南。 。 Next.js 官方文档 阅读此处 :直接从源头深入探讨服务器操作的工作原理、最佳实践和潜力。 。 Next.js 中的服务器操作 阅读更多 :了解应用程序路由器的功能,特别是有关 React 服务器组件的功能。 。 应用程序路由器 探索这里 :关于如何最好地利用服务器组件来优化性能和灵活性的入门知识。 。 React 服务器组件 在这里学习 结束 首先,非常 与我一起穿越 世界的这个错综复杂的迷宫。如果您已经做到了这一步,那么恭喜您!如果你浏览了某些部分,我不会责怪你——有时候我想跳过写它们! 感谢您 Next.js 从很多方面来说,构建实时应用程序就像坐过山车一样。有时候,我感觉自己像个编码天才,而另一些时候,我质疑每一个导致我成为开发人员的人生选择。 你是否有过这样的经历:你花了几个小时调试一个问题,却发现你漏掉了一个分号?或者当您不小心删除了代码的重要部分并希望生活有一个 Ctrl + Z 时? 哦,编程的乐趣! 但事情是这样的:在所有的捂脸和偶尔的拉扯头发的过程中,看到你的创作实时变为现实,有一种难以形容的魔力。当你的代码运行没有错误时,这是一种微小的喜悦火花,当用户喜欢你的应用程序时的满足感,以及当你从头开始构建一些东西时的自豪感。 对于每一位正在阅读本文的初露头角的开发人员:挫折、挫败感以及“为什么这不起作用!?”时刻是我们旅程的重要组成部分。它们并不是你失败的迹象,而是变得更好的垫脚石。 因此,下次当你的代码拒绝配合时,深吸一口气,喝点咖啡(或茶,我不评判,我自己就是 粉丝),并记住你并不孤单。 matecocido 的 不断突破界限,不断学习,并记住每一行代码,无论它是否有效,都会为您的开发者故事增添一章。 如果你需要一个笑声或一个肩膀来哭泣(当然,实际上是这样),请知道我曾经在那里,做过这些,并且已经足够沮丧,以至于考虑将我的笔记本电脑扔出窗外! 这是为了更多的编码冒险和更少的分号引起的错误! 干杯,祝编码愉快!