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

NextJS 15(App Router)配置MSW客户端Worker遇问题求助

NextJS 15 App Router 配置 MSW 客户端 Worker 解决方案

核心问题分析

你的问题主要出在三个点:

  1. 环境混淆:直接在服务端组件(RootLayout)中调用浏览器环境的 worker.start(),导致MSW报错服务端安装
  2. 初始化时机:Worker未在页面请求发起前完成启动,导致初始请求未被拦截
  3. 热重载冲突:NextJS开发环境热重载会重复执行组件逻辑,引发Worker重复启动或异常

分步解决

1. 生成MSW浏览器Worker脚本

首先确保public目录下存在MSW的Worker文件,执行以下命令生成:

npx msw init public --save

2. 创建客户端专属的Mock初始化组件

新建 @src/app/ClientMockInitializer.tsx,用"use client"限定仅在浏览器环境执行:

"use client";

import { useEffect, useState } from "react";
import { worker } from "@/src/shared/api/mocks/browser";

export default function ClientMockInitializer({
  children,
}: {
  children: React.ReactNode;
}) {
  const [isMockReady, setIsMockReady] = useState(false);

  useEffect(() => {
    // 仅在开发环境启用Mock
    if (process.env.NODE_ENV !== "development") {
      setIsMockReady(true);
      return;
    }

    // 避免热重载重复启动Worker
    if (worker.isStarted()) {
      setIsMockReady(true);
      return;
    }

    const startWorker = async () => {
      try {
        await worker.start({
          serviceWorker: { url: "/mockServiceWorker.js" }, // 对应public目录下的脚本
          onUnhandledRequest: "bypass", // 跳过未配置的请求,避免干扰正常接口
        });
        setIsMockReady(true);
      } catch (err) {
        console.error("MSW Worker启动失败:", err);
        setIsMockReady(true); // 即使启动失败也允许页面加载
      }
    };

    startWorker();

    // 热重载时停止Worker,避免内存泄漏
    return () => {
      if (worker.isStarted()) worker.stop();
    };
  }, []);

  // 等待Worker初始化完成再渲染页面,确保请求被拦截
  if (!isMockReady) {
    return <div>Loading mock data...</div>;
  }

  return <>{children}</>;
}

3. 修改RootLayout,集成客户端Mock组件

调整服务端Mock的启动逻辑,并将客户端初始化组件包裹在页面内容外层:

import type { Metadata } from "next"
import "./globals.css"
import { Providers } from "@/src/app"
import { server } from "@/src/shared/api/mocks/server"
import ClientMockInitializer from "./ClientMockInitializer";

export const metadata: Metadata = {
   title: "Create Next App",
   description: "Generated by create next app",
}

// 服务端Mock仅在开发环境启动
if (process.env.NODE_ENV === "development") {
  server.listen({ onUnhandledRequest: "bypass" });
}

export default function RootLayout({
   children,
}: Readonly<{
   children: React.ReactNode
}>) {
  return (
    <html lang="en">
      <body>
        <Providers>
          <ClientMockInitializer>{children}</ClientMockInitializer>
        </Providers>
      </body>
    </html>
  );
}

关键说明

  • 用"use client"强制组件在浏览器环境执行,彻底避免服务端调用浏览器API的错误
  • 通过状态控制页面渲染时机,确保Worker初始化完成后再发起请求,解决数据仅显示几秒的问题
  • 增加热重载清理逻辑,避免Worker重复启动导致的异常
  • onUnhandledRequest: "bypass"配置可防止未Mock的请求被MSW拦截报错

内容的提问来源于stack exchange,提问作者Curry

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 14:40:09