Next.js中间件出现window is not defined错误排查求助
Next.js中间件使用Appwrite时出现
window is not defined错误 技术栈
- Appwrite(后端)
- Next.js
在middleware.ts中实现路由保护,调用getCurrentUser检查登录状态时触发window is not defined错误,但该方法在服务端组件中可正常运行,代码未直接使用window对象。
核心代码
middleware.ts
const NOT_LOGGED_IN_ROUTES = ["/login"]; const LOGGED_IN_ROUTES = ["/edit-profile"]; export async function middleware(request: NextRequest) { const currentPath = request.nextUrl.pathname; const { AppwriteServices } = await import("@/AppwriteServices"); const appwriteServices = new AppwriteServices(); const isUserLoggedIn = (await appwriteServices.getCurrentUser()) !== null; if (isUserLoggedIn && NOT_LOGGED_IN_ROUTES.includes(currentPath)) { return NextResponse.redirect(new URL("/", request.url)); } if (!isUserLoggedIn && LOGGED_IN_ROUTES.includes(currentPath)) { return NextResponse.redirect(new URL("/login", request.url)); } }
AppwriteServices关键方法
getCurrentUser
getCurrentUser = async () => { try { await this.setSession(); return await account.get(); } catch (error) { // catch分支代表用户未登录,不抛出错误 } return null; };
setSession
private async setSession() { try { const cookieValue = await this.getCookieValue(); const authCookies = { [`a_session_${AppwriteProject.toLowerCase()}`]: cookieValue, }; client.headers["X-Fallback-Cookies"] = JSON.stringify(authCookies); } catch (error) { throw new Error((<Error>error).message); } }
getCookieValue
private async getCookieValue() { try { const { cookies } = await import("next/headers"); const sessionNames = [ `a_session_${AppwriteProject.toLowerCase()}`, `a_session_${AppwriteProject.toLowerCase()}_legacy`, ]; const cookieStore = cookies(); const hash = cookieStore.get(sessionNames[0]) ?? cookieStore.get(sessionNames[1]) ?? null; return hash?.value || ""; } catch (error) { throw new Error((<Error>error).message); } }
问题根源
Appwrite JavaScript SDK默认会尝试从浏览器localStorage或window对象读取会话,即便手动设置了X-Fallback-Cookies头,客户端初始化时的部分逻辑仍可能在边缘运行时(中间件环境)触发对window的访问。此外,中间件的边缘环境与服务端组件的Node.js环境存在差异,旧版SDK的降级逻辑可能未适配边缘环境。
解决方案
1. 显式初始化Appwrite客户端,禁用自动会话存储
修改Appwrite客户端初始化代码,关闭自动会话持久化,避免SDK尝试访问浏览器API:
import { Client, Account } from "appwrite"; const client = new Client() .setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!) .setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT!); // 禁用自动会话存储,强制使用手动设置的Cookie client.setSession("");
2. 中间件中直接处理Cookie,绕过封装层
跳过AppwriteServices封装,直接在中间件中提取Cookie并验证会话:
// middleware.ts import { NextRequest, NextResponse } from "next/server"; import { Client, Account } from "appwrite"; const NOT_LOGGED_IN_ROUTES = ["/login"]; const LOGGED_IN_ROUTES = ["/edit-profile"]; export async function middleware(request: NextRequest) { const currentPath = request.nextUrl.pathname; const projectId = process.env.NEXT_PUBLIC_APPWRITE_PROJECT?.toLowerCase() || ""; const sessionNames = [`a_session_${projectId}`, `a_session_${projectId}_legacy`]; // 从请求Cookie中获取会话 const sessionCookie = request.cookies.get(sessionNames[0]) || request.cookies.get(sessionNames[1]); let isUserLoggedIn = false; if (sessionCookie) { const client = new Client() .setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!) .setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT!); // 设置会话Cookie头 client.headers["X-Fallback-Cookies"] = JSON.stringify({ [sessionCookie.name]: sessionCookie.value }); try { const account = new Account(client); await account.get(); isUserLoggedIn = true; } catch { // 会话无效,判定为未登录 } } // 路由拦截逻辑 if (isUserLoggedIn && NOT_LOGGED_IN_ROUTES.includes(currentPath)) { return NextResponse.redirect(new URL("/", request.url)); } if (!isUserLoggedIn && LOGGED_IN_ROUTES.includes(currentPath)) { return NextResponse.redirect(new URL("/login", request.url)); } }
3. 升级Appwrite SDK到最新版本
执行命令升级SDK,确保边缘环境适配逻辑完整:
npm update appwrite
验证
修改后,中间件直接在边缘环境处理Cookie,显式控制Appwrite客户端的会话逻辑,避免SDK自动访问window对象,同时适配中间件的运行环境。
内容的提问来源于stack exchange,提问作者Pratik Dev
相关产品推荐
相关产品推荐

