Next.js 13 中使用 res.redirect() 无法跳转的问题排查
问题:Next.js中调用后端跳转接口无法生效
我正在实现设置昵称和头像的功能,操作成功后调用后端接口请求授权并跳转至首页。解决CORS错误后,页面仍然无法跳转,怀疑是Next.js的SPA特性导致刷新式跳转不生效,想知道具体原因及解决办法。
相关代码
Next.js /init/page.tsx 代码
const submitAvatar = async () => { const formData = new FormData(); if (!avatarFile) { alert('You are using default avatar'); } else { formData.append('avatar', avatarFile); } try { const response = await fetch('http://localhost:3001/user/photo', { method: 'POST', headers: { 'Authorization': `Bearer ${value}`, }, body: formData, }); try { if (response.ok) { await fetch('http://localhost:3001/auth/init', { //request redirect here method: 'GET', headers: { 'Authorization': `Bearer ${value}`, }, }) } } catch (error) { console.error('redirect', error); } } catch (error) { console.error(error); } };
后端接口代码
@Get('init') @UseGuards(InitAuthGuard) async getInit( @GetUser() user: UserEntity, @Res() res: Response ){ const {Token} = await this.authService.existingSign(user.uid); res.cookie('Token', Token); res.redirect('http://localhost:3000'); }
Next.js CORS配置(next.config.js)
/** @type {import('next').NextConfig} */ const nextConfig = { async headers() { return [ { source: '/(.*)', // Match all paths headers: [ { key: 'Access-Control-Allow-Origin', value: '*', // Adjust this based on your needs }, { key: 'Access-Control-Allow-Credentials', value: 'true', }, { key: 'Access-Control-Allow-Headers', value: 'Authorization', // Include any other headers you need }, ], }, ]; } } module.exports = nextConfig
原因分析
核心问题确实和Next.js的SPA特性相关:
- 前端用
fetch发起异步请求时,浏览器会在后台处理请求响应,不会自动执行后端返回的redirect指令——redirect是针对浏览器直接访问的场景设计的,不适用于AJAX/fetch这类异步请求。 - 跨域场景下,你的
fetch请求未配置credentials: 'include',导致后端设置的Cookie无法被浏览器正确保存,即使跳转也无法携带授权信息。
解决办法
方案一:前端处理跳转(推荐)
后端仅完成Cookie设置和授权逻辑,跳转操作由前端主动触发,符合SPA的交互逻辑:
- 修改后端接口:
@Get('init') @UseGuards(InitAuthGuard) async getInit( @GetUser() user: UserEntity, @Res() res: Response ){ const {Token} = await this.authService.existingSign(user.uid); res.cookie('Token', Token, { domain: 'localhost', httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'lax' }); res.status(200).json({success: true}); }
- 修改前端
submitAvatar方法:
- 添加
credentials: 'include'确保跨域Cookie正常保存 - 使用Next.js的
useRouter实现无刷新跳转:
import { useRouter } from 'next/navigation'; const router = useRouter(); const submitAvatar = async () => { const formData = new FormData(); if (!avatarFile) { alert('You are using default avatar'); } else { formData.append('avatar', avatarFile); } try { const response = await fetch('http://localhost:3001/user/photo', { method: 'POST', headers: { 'Authorization': `Bearer ${value}`, }, body: formData, credentials: 'include' }); if (response.ok) { const initResponse = await fetch('http://localhost:3001/auth/init', { method: 'GET', headers: { 'Authorization': `Bearer ${value}`, }, credentials: 'include' }); if (initResponse.ok) { router.push('/'); } } } catch (error) { console.error(error); } };
方案二:直接让浏览器访问后端接口(不推荐)
如果必须保留后端的redirect逻辑,可以放弃fetch,直接让浏览器发起页面跳转请求:
const submitAvatar = async () => { // ... 原有头像上传逻辑 try { const response = await fetch('http://localhost:3001/user/photo', { method: 'POST', headers: { 'Authorization': `Bearer ${value}`, }, body: formData, credentials: 'include' }); if (response.ok) { window.location.href = `http://localhost:3001/auth/init?token=${value}`; } } catch (error) { console.error(error); } };
这种方式会强制刷新页面,破坏SPA的流畅体验,仅作为临时替代方案。
内容的提问来源于stack exchange,提问作者z2ouu
相关产品推荐
相关产品推荐

