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

Next.js App Router:SSR与Axios、Cookie及状态管理问题咨询

Next.js App Router 航班预订系统 SSR 实践问题解答

背景与已尝试方案

我正在使用Next.js(App Router)构建航班预订系统,希望采用Server-Side Rendering(SSR),但在API调用、Cookie及状态管理方面遇到了问题。

已实现的核心代码如下:

src/utils/api.ts

import axios from "axios";
import { cookies } from "next/headers";

const api = axios.create({
  baseURL: process.env.NEXT_PUBLIC_API_URL,
  headers: {
    "Content-Type": "application/json",
  },
  withCredentials: true,
});

api.interceptors.request.use((config) => {
  const token = cookies().get("token")?.value;
  if (token && config.headers) {
    config.headers["Authorization"] = `Bearer ${token}`;
  }
  return config;
});

export default api;

src/services/userService.ts

import api from "../utils/api";
import { AxiosResponse } from "axios";

export const registerUser = async (userData: any): Promise<any> => {
  const res: AxiosResponse<any> = await api.post(
    "/api/users/register",
    userData
  );
  return res.data;
};

export const loginUser = async (credentials: any): Promise<any> => {
  const res: AxiosResponse<any> = await api.post(
    "/api/users/login",
    credentials
  );
  return res.data;
};

export const logoutUser = async (): Promise<any> => {
  const res: AxiosResponse<any> = await api.post("/api/users/logout");
  return res.data;
};

export const getUserProfile = async (): Promise<any> => {
  const res: AxiosResponse<any> = await api.get("/api/users/me");
  return res.data;
};

遇到的问题与困惑

问题

  1. 客户端与服务端组件冲突:传递Cookie时触发Client Component错误,不确定是否需要维护两套Axios实例。
  2. Cookie处理矛盾:SSR用Next.js headers()读取Cookie,CSR靠Axios withCredentials自动发送,两者结合报错。
  3. 状态管理选型:不确定航班预订系统(含搜索表单、结果、预订详情)是否需要Redux/Zustand,还是仅靠SSR即可。

困惑

  • 是否需要维护SSR和CSR两个独立Axios实例?
  • 如何在不转全客户端组件的前提下,在SSR中正确传递Cookie?
  • 航班预订系统是否必须用状态管理,还是SSR+服务端组件可覆盖大部分场景?

解决方案与最佳实践

一、API调用与Cookie处理优化

1. 无需两套Axios实例,单实例适配两端

通过环境判断区分服务端/客户端逻辑,复用同一个Axios实例,避免冗余维护:

// src/utils/api.ts
import axios from "axios";
import { cookies } from "next/headers";

const createApiInstance = () => {
  const isServer = typeof window === 'undefined';
  const baseURL = process.env.NEXT_PUBLIC_API_URL;

  const instance = axios.create({
    baseURL,
    headers: {
      "Content-Type": "application/json",
    },
    withCredentials: !isServer, // 客户端开启自动携带Cookie,服务端不需要
  });

  instance.interceptors.request.use((config) => {
    if (isServer) {
      // 服务端:从Next.js cookies中获取token
      const token = cookies().get("token")?.value;
      if (token && config.headers) {
        config.headers["Authorization"] = `Bearer ${token}`;
      }
    }
    // 客户端:浏览器自动携带Cookie,无需手动处理
    return config;
  });

  return instance;
};

const api = createApiInstance();
export default api;

2. 不转全客户端组件的Cookie传递方案

  • 服务端组件(Server Component):直接使用上述API实例即可,服务端运行时cookies()可正常调用,不会触发客户端报错。
  • 客户端组件(Client Component):禁止在组件顶层代码调用依赖服务端API的逻辑,改用两种方式:
    • 父级服务端组件获取数据后,通过props传递给客户端组件;
    • 在客户端组件内用useEffect触发API调用(此时实例自动切换为客户端模式,依赖withCredentials传Cookie)。

示例客户端组件调用:

'use client';
import { useEffect, useState } from 'react';
import { getUserProfile } from '../services/userService';

export default function UserProfile() {
  const [profile, setProfile] = useState(null);

  useEffect(() => {
    const fetchProfile = async () => {
      const data = await getUserProfile();
      setProfile(data);
    };
    fetchProfile();
  }, []);

  return <div>{profile?.name}</div>;
}

二、状态管理的判断标准

航班预订系统无需一开始就引入全局状态管理,按场景逐步判断:

优先用SSR+服务端组件处理的场景

  • 页面初始数据(如用户登录状态、航班列表初始加载):直接在服务端组件内写异步逻辑获取数据,通过props传递。
  • 静态/准静态数据(如机场列表、航空公司信息):用fetch的cache配置做缓存,或用静态生成(SSG)。

需要引入状态管理的场景

当出现以下情况时,再考虑Redux/Zustand等工具:

  • 跨组件共享状态:如搜索参数(出发地、日期)需要在搜索页、结果页、预订页同步更新。
  • 客户端临时状态持久化:如用户筛选航班、添加行李选项等无需回传服务器的交互状态,需在多组件间保持同步。
  • 复杂流程状态:如多步骤预订流程(填乘客信息、选座、支付),需跟踪步骤进度并支持撤销/前进操作。

单页面内的局部状态(如搜索表单输入),用React原生useState/useReducer完全足够。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 12:55:57