You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS 13 App目录下请求处理最佳实践及前后端边界疑问

Next.js 13 App Directory 请求处理最佳实践与前后端边界界定

请求处理最佳实践

Next.js 13 App Directory的核心是**服务器组件(Server Components)和客户端组件(Client Components)**的区分,请求处理的最佳实践要围绕这两类组件展开:

1. 服务器组件:直接调用业务/数据模块,跳过API层

服务器组件默认运行在服务器端,完全可以直接调用内部的业务逻辑模块(比如鉴权、数据库操作模块),不需要通过HTTP请求走API路由。这种方式减少了网络开销,还能直接利用服务器端的资源(比如数据库连接、环境变量)。

举个例子,在服务器组件中直接调用鉴权模块获取当前用户:

// app/profile/page.js(默认是服务器组件)
import { getCurrentUser } from '@/services/auth';

async function ProfilePage() {
  // 直接调用服务器端鉴权模块,无需API请求
  const user = await getCurrentUser();
  
  return (
    <div>
      <h1>我的资料</h1>
      <p>用户名:{user.username}</p>
    </div>
  );
}

export default ProfilePage;

2. 客户端组件:通过封装的API模块处理请求,避免组件内硬编码

客户端组件(标记'use client')运行在浏览器,需要和服务器通信时,不要直接在组件里写fetch或axios逻辑,建议把请求逻辑封装到独立的API模块(比如@/api/auth.js、@/api/user.js)。

这么做的好处:

  • 复用性:多个组件可以共用同一套请求逻辑,避免重复代码
  • 可维护性:鉴权(比如携带Token)、错误处理、请求头统一配置都集中在模块里,改一处全生效
  • 可读性:组件只关注UI渲染和交互逻辑,请求逻辑剥离到专门模块

举个例子:
首先封装API模块:

// @/api/user.js
import { getAuthToken } from '@/utils/client-auth';

export async function updateUserProfile(profileData) {
  const token = getAuthToken();
  const res = await fetch('/api/user/profile', {
    method: 'PUT',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${token}`
    },
    body: JSON.stringify(profileData)
  });

  if (!res.ok) {
    const error = await res.json();
    throw new Error(error.message || '更新失败');
  }

  return res.json();
}

然后在客户端组件中调用:

// app/profile/edit/page.js
'use client';

import { useState } from 'react';
import { updateUserProfile } from '@/api/user';

function EditProfilePage() {
  const [username, setUsername] = useState('');

  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      await updateUserProfile({ username });
      alert('更新成功');
    } catch (err) {
      alert(err.message);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={username}
        onChange={(e) => setUsername(e.target.value)}
        placeholder="输入新用户名"
      />
      <button type="submit">保存</button>
    </form>
  );
}

export default EditProfilePage;

特殊情况:组件内直接处理请求

如果是非常简单、无复用需求的一次性请求(比如某个独立组件仅需获取一次静态配置),可以直接在客户端组件内写fetch,但这种场景尽量少用,优先保持代码的可维护性。

前后端边界的界定

在Next.js 13 App Directory中,前后端边界不再是物理文件的分隔,而是运行环境的边界:

1. 服务器端边界(仅在服务器运行)

  • 所有未标记'use client'的组件(默认服务器组件)
  • app/api/目录下的API路由(处理客户端HTTP请求的中间层)
  • 服务器端专属模块:数据库操作、鉴权核心逻辑(比如验证会话、查询用户权限)、业务逻辑处理、访问服务器环境变量的代码

这些代码永远不会被打包到客户端,完全运行在服务器,你可以像传统后端一样处理数据、调用服务。

2. 客户端边界(仅在浏览器运行)

  • 标记'use client'的组件
  • 客户端专属模块:表单验证、UI交互逻辑、客户端状态管理(比如Zustand、Redux)、本地存储操作、处理用户输入的代码

这些代码负责处理用户交互,无法直接访问服务器资源(比如数据库),必须通过API路由或服务器组件传递数据。

关键:API路由的角色

API路由是前后端通信的桥梁:当客户端组件需要和服务器交互时,通过API路由发送HTTP请求,API路由内部调用服务器端的业务逻辑,再把结果返回给客户端。而服务器组件则可以跳过这一步,直接调用业务逻辑,这是App Directory架构的核心优化点。

内容的提问来源于stack exchange,提问作者Fares

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 22:42:26