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

Next.js服务器操作能否处理所有客户端交互?Cookie认证如何实现?

统一Next.js前后端请求的认证方案(DRF + Simple JWT)

针对你遇到的服务器组件/客户端组件请求认证逻辑重复的问题,有几个更简洁的统一方案,不用维护两套请求代码:

方案1:封装环境无关的请求工具函数

写一个通用的请求工具,自动判断当前运行环境(服务器/客户端)并获取token,实现一套代码适配两种场景。

步骤1:封装token获取函数

创建utils/getAuthToken.js:

import { headers } from 'next/headers';
import Cookies from 'js-cookie';

export const getAuthToken = () => {
  // 服务器端:从请求头的cookie中提取token
  if (typeof window === 'undefined') {
    const cookieStr = headers().get('cookie');
    if (!cookieStr) return null;
    // 匹配你的Simple JWT token字段(假设存在access_token)
    const tokenMatch = cookieStr.match(/access_token=([^;]+)/);
    return tokenMatch ? tokenMatch[1] : null;
  }
  // 客户端:用js-cookie读取token
  return Cookies.get('access_token');
};

步骤2:统一请求工具

创建utils/apiRequest.js:

import { getAuthToken } from './getAuthToken';

export const apiRequest = async (url, options = {}) => {
  const token = getAuthToken();
  const requestHeaders = {
    'Content-Type': 'application/json',
    ...options.headers,
    // 携带认证头(如果有token)
    ...(token && { Authorization: `Bearer ${token}` }),
  };

  const response = await fetch(`${process.env.NEXT_PUBLIC_DJANGO_API_URL}${url}`, {
    ...options,
    headers: requestHeaders,
  });

  // 统一错误处理(比如token过期、权限不足等)
  if (!response.ok) {
    const errorData = await response.json().catch(() => null);
    throw new Error(errorData?.detail || `请求失败: ${response.status}`);
  }

  return response.json();
};

现在不管是服务器组件还是客户端组件,直接调用apiRequest即可,无需区分环境:

// 服务器组件中获取群组
const groups = await apiRequest('/groups/');

// 客户端组件中提交表单
const handleSubmit = async () => {
  await apiRequest('/groups/', {
    method: 'POST',
    body: JSON.stringify({ name: '新群组' })
  });
};

方案2:用Next.js API路由做请求代理

把所有前端请求先转发到Next.js的API路由,再由API路由统一处理认证并转发到Django后端。这样前端只需要请求自己的API,不用关心认证逻辑。

创建代理路由(App Router示例)

创建app/api/proxy/[...path]/route.js:

import { headers } from 'next/headers';
import { NextResponse } from 'next/server';

// 处理GET请求
export async function GET(request, { params }) {
  const targetUrl = `${process.env.DJANGO_API_URL}/${params.path.join('/')}`;
  const cookie = headers().get('cookie');

  const djangoResponse = await fetch(targetUrl, {
    headers: {
      // 传递cookie给Django,让它自行解析token
      ...(cookie && { Cookie: cookie }),
    },
  });

  const data = await djangoResponse.json();
  return NextResponse.json(data, { status: djangoResponse.status });
}

// 同理实现POST/PUT/DELETE等方法
export async function POST(request, { params }) {
  const targetUrl = `${process.env.DJANGO_API_URL}/${params.path.join('/')}`;
  const cookie = headers().get('cookie');
  const body = await request.json();

  const djangoResponse = await fetch(targetUrl, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      ...(cookie && { Cookie: cookie }),
    },
    body: JSON.stringify(body),
  });

  const data = await djangoResponse.json();
  return NextResponse.json(data, { status: djangoResponse.status });
}

前端请求时直接调用这个代理路由:

// 服务器/客户端组件通用
const groups = await fetch('/api/proxy/groups').then(res => res.json());

这种方式的好处是:认证逻辑完全集中在Next.js的API层,前端代码无需处理token;还能在代理层添加额外逻辑(比如token自动刷新、请求日志、数据格式转换)。

方案3:用Server Actions统一客户端交互(App Router专属)

如果用Next.js App Router,可以把所有需要认证的客户端操作(比如点击按钮提交表单)都通过Server Actions实现,让服务器端处理所有请求,彻底统一环境。

编写Server Action

创建actions/groupActions.js:

'use server';

import { headers } from 'next/headers';

export async function createGroup(formData) {
  const cookie = headers().get('cookie');
  const response = await fetch(`${process.env.DJANGO_API_URL}/groups/`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      ...(cookie && { Cookie: cookie }),
    },
    body: JSON.stringify({
      name: formData.get('name'),
      // 其他字段
    }),
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.detail || '创建群组失败');
  }

  return response.json();
}

客户端组件调用Action

'use client';

import { createGroup } from '@/actions/groupActions';

export default function CreateGroupForm() {
  const handleSubmit = async (e) => {
    e.preventDefault();
    const formData = new FormData(e.target);
    try {
      await createGroup(formData);
      // 成功后的逻辑(比如刷新列表)
    } catch (err) {
      alert(err.message);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" name="name" placeholder="群组名称" required />
      <button type="submit">创建群组</button>
    </form>
  );
}

这种方式下,客户端组件完全不用处理token,所有请求都通过服务器端发起,和服务器组件的请求逻辑完全一致,彻底消除环境差异。


内容的提问来源于stack exchange,提问作者Kilan Van Loo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 16:08:11