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; };
遇到的问题与困惑
问题
- 客户端与服务端组件冲突:传递Cookie时触发Client Component错误,不确定是否需要维护两套Axios实例。
- Cookie处理矛盾:SSR用Next.js
headers()读取Cookie,CSR靠AxioswithCredentials自动发送,两者结合报错。 - 状态管理选型:不确定航班预订系统(含搜索表单、结果、预订详情)是否需要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
相关产品推荐
相关产品推荐

