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
相关产品推荐
相关产品推荐

