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

Next.js服务端fetch GET请求携带Cookie失效问题排查

问题根因

getServerSideProps 运行在Next.js的Node.js服务端环境,而非用户浏览器端:

  • 浏览器本地存储的Cookie只会在浏览器主动发起请求时自动携带,服务端执行的fetch代码没有权限直接读取用户浏览器侧的Cookie
  • 你配置的credentials: 'include'仅对浏览器环境的fetch生效,服务端发起HTTP请求时不会自动附带用户的登录态Cookie,因此Express后端收不到有效凭证,自然返回loggedIn: false
  • 直接在浏览器地址栏访问接口能返回正确结果,是因为该请求由浏览器直接发起,自动携带了本地存储的对应Cookie
  • 额外注意:你贴的代码中重定向判断写的是if (!true),该条件恒成立,无论接口返回什么结果都会触发重定向,属于明显笔误。
解决方案

方案1:服务端鉴权:手动转发请求上下文中的Cookie

getServerSideProps 入参包含请求上下文对象,其中context.req.headers.cookie就是用户访问当前Next页面时,请求头自带的Cookie字符串,只需将该字段手动添加到发往后端的fetch请求头中即可。
修改后的getServerSideProps代码示例:

export async function getServerSideProps(context) {
  // 从请求上下文提取用户携带的Cookie
  const userCookie = context.req.headers.cookie || ''
  const requestOption = {
    method: 'GET',
    headers: {
      Cookie: userCookie,
      'Content-Type': 'application/json'
    },
  }

  const loggedIn = await fetch(
    'http://localhost:3001/api/auth/loggedIn',
    requestOption
  )
  .then(res => res.json())
  .then(json => json.loggedIn)

  console.log(loggedIn)

  // 修正原代码的笔误判断
  if (!loggedIn) {
    return {
      redirect: {
        destination: '/login',
        permanent: false,
      },
    }
  }

  return {
    props: {},
  }
}

方案2:客户端鉴权:将鉴权逻辑移到浏览器侧执行

如果不需要在服务端渲染阶段完成登录态校验,可以把鉴权请求移到页面组件的客户端逻辑中执行,此时fetch运行在浏览器环境,配置credentials: 'include'即可自动携带Cookie,无需手动处理。
代码示例:

// 页面组件内引入依赖
import { useEffect, useState } from 'react'
import { useRouter } from 'next/router'
import Navbar from '../components/Navbar'
import HeroDash from '../components/hero_dash'
import CookieBanner from '../components/CookieBanner'
import Tutorial from '../components/Tutorial'
import Outset from '../components/Outset'

const Home: NextPage = () => {
  const router = useRouter()
  const [searchIcon, setSearchIcon] = useState(false)
  const handleSearchClick = () => {
    setSearchIcon(!searchIcon)
    console.log(searchIcon)
  }

  useEffect(() => {
    const checkLoginStatus = async () => {
      const res = await fetch('http://localhost:3001/api/auth/loggedIn', {
        method: 'GET',
        mode: 'cors',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' }
      })
      const { loggedIn } = await res.json()
      if (!loggedIn) {
        router.push('/login')
      }
    }
    checkLoginStatus()
  }, [router])

  return (
    <>
      <div className="h-screen bg-cultured dark:bg-raisin">
        <Navbar />
        <HeroDash />
        <div className="columns-2 gap-x-10 px-10">
          <div className="break-after-column">
            <Outset />
          </div>
          <div className="">
            <Tutorial />
          </div>
        </div>
        <div className="flex justify-center">
          <CookieBanner hidden={true} />
        </div>
      </div>
    </>
  )
}

export default Home

后端配置校验

无论使用哪种方案,都需要确保Express后端的CORS和Cookie配置符合跨域携带凭证的要求:

  • CORS配置不能将origin设为*通配符,需明确指定前端服务地址(本地开发一般为http://localhost:3000)
  • CORS需开启credentials: true,允许跨域请求携带Cookie
  • Cookie下发时,本地开发环境不要设置Secure属性(仅HTTPS环境生效),sameSite建议设为lax,避免跨站请求被浏览器拦截Cookie

Express端CORS配置示例:

const cors = require('cors')
app.use(cors({
  origin: 'http://localhost:3000', // 替换为实际前端服务地址
  credentials: true
}))

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 01:01:00