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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 03:52:17