Next.js 13 API路由无法在Laravel 11会话中持久化数据
问题:Laravel 11 + Next.js pages/api 会话无法保持,每次请求创建新会话
环境配置信息
后端Laravel 11配置
.env 文件
... SESSION_DRIVER=database SESSION_LIFETIME=120 SESSION_ENCRYPT=false SESSION_PATH=/ SESSION_DOMAIN=localhost SANCTUM_STATEFUL_DOMAINS=localhost:3000 ...
bootstrap/app.php(Laravel 11无kernel.php)
... ->withRouting( web: __DIR__.'/../routes/web.php', api: __DIR__.'/../routes/api.php', commands: __DIR__.'/../routes/console.php', health: '/up', ) ->withMiddleware(function (Middleware $middleware) { $middleware->api(prepend: [ \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, ]); $middleware->alias([ 'verified' => \App\Http\Middleware\EnsureEmailIsVerified::class, ]); // }) ->withExceptions(function (Exceptions $exceptions) { // })->create(); ...
cors.php(Laravel 11默认无此文件,手动创建)
<?php return [ 'paths' => ['api/*', 'sanctum/csrf-cookie', 'login', 'logout', 'register', 'forgot-password'], 'allowed_methods' => ['*'], 'allowed_origins' => ['http://localhost:3000'], 'allowed_origins_patterns' => [], 'allowed_headers' => ['*'], 'exposed_headers' => [], 'max_age' => 0, 'supports_credentials' => true, ];
前端配置
Axios 实例配置
import Axios from 'axios' const axios = Axios.create({ baseURL: process.env.NEXT_PUBLIC_BACKEND_URL, headers: { "X-Requested-With": "XMLHttpRequest" }, withCredentials: true, withXSRFToken: true }) export default axios;
Next.js pages/api 路由代码
import type { NextApiRequest, NextApiResponse } from "next"; import axios from '@/lib/axios' type Data = { name: string; }; export default async function handler( req: NextApiRequest, res: NextApiResponse<Data>, ) { const url = `${process.env.NEXT_PUBLIC_BACKEND_URL}/api/increase-cart`; axios .post(url, req.body) .then(res => console.log(res.data)) .catch(error => console.log(error)) res.status(200).json({ name: "John Doe" }); }
核心问题
通过Next.js的pages/api路由调用Laravel后端接口时,每次请求都会创建新的会话,无法在同一个会话中更新购物车数据。
解决方案
1. 传递客户端Cookie到后端
Next.js的API路由运行在服务端,默认不会携带客户端的会话Cookie,需要从请求对象中提取并传递给axios:
export default async function handler( req: NextApiRequest, res: NextApiResponse<Data>, ) { const url = `${process.env.NEXT_PUBLIC_BACKEND_URL}/api/increase-cart`; try { const response = await axios.post(url, req.body, { headers: { Cookie: req.headers.cookie || '' // 传递客户端Cookie到后端 } }); console.log(response.data); res.status(200).json(response.data); } catch (error) { console.error(error); res.status(error.response?.status || 500).json({ error: '请求失败' }); } }
2. 确保CSRF Token正确传递
使用Sanctum时,需先在客户端页面初始化CSRF Token,并在API路由中传递对应请求头:
- 在页面组件中获取CSRF Token(如
_app.tsx):
import axios from '@/lib/axios'; import { useEffect } from 'react'; function MyApp({ Component, pageProps }) { useEffect(() => { const fetchCsrfToken = async () => { await axios.get('/sanctum/csrf-cookie'); }; fetchCsrfToken(); }, []); return <Component {...pageProps} />; } export default MyApp;
- 在API路由中传递
X-XSRF-TOKEN头:
export default async function handler( req: NextApiRequest, res: NextApiResponse<Data>, ) { const url = `${process.env.NEXT_PUBLIC_BACKEND_URL}/api/increase-cart`; try { const response = await axios.post(url, req.body, { headers: { Cookie: req.headers.cookie || '', 'X-XSRF-TOKEN': req.headers['x-xsrf-token'] || '' } }); console.log(response.data); res.status(200).json(response.data); } catch (error) { console.error(error); res.status(error.response?.status || 500).json({ error: '请求失败' }); } }
3. 验证会话与Sanctum配置
- 确认
SESSION_DOMAIN为localhost(无需加端口),SANCTUM_STATEFUL_DOMAINS包含localhost:3000,当前配置已满足要求。 - 确保
cors.php中supports_credentials为true,allowed_origins包含前端地址http://localhost:3000,当前配置正确。
总结
问题根源是Next.js API路由默认不携带客户端会话Cookie和CSRF Token,导致Laravel无法识别已有会话。通过在API路由中传递客户端的Cookie和CSRF Token,即可实现会话保持,正常更新购物车数据。
内容的提问来源于stack exchange,提问作者Pranay Aryal
相关产品推荐
相关产品推荐

