前端项目如何接入api mock平台——使用 Service Worker 实现请求拦截与 Mock 数据

470 阅读3分钟

使用 Service Worker 实现请求拦截与 Mock 数据

背景介绍

在前端开发过程中,我们经常需要在后端 API 尚未完成时模拟数据进行开发和测试。传统的 Mock 方案往往需要修改代码或使用特定的 Mock 库,增加了代码复杂度和维护成本。本文介绍的 Service Worker 方案通过拦截网络请求实现无侵入式的 API Mock,使得前端开发可以更加灵活和高效。

实现原理

该方案利用 Service Worker 的网络拦截能力,拦截指定的 API 请求并将其转发到 Mock 服务器。具体流程如下:

---
title: Service Worker 请求 Mock 流程图
---
flowchart TB
    A([开始]) --> B[注册 Service Worker\n传入 Mock 配置]
    B --> C[Service Worker 监听 fetch 事件]
    C --> D{请求匹配\nMock 规则?}
    D -->|是| E[构造 Mock 响应头/体]
    D -->|否| F[放行原始请求]
    E --> G[返回 Mock 响应]
    F --> G
    G --> H([结束])

    style A fill:#4CAF50,color:white
    style H fill:#FF5722,color:white
    style D stroke:#2196F3,stroke-width:2px
  1. 注册 Service Worker 并传入 Mock 配置
  2. Service Worker 监听 fetch 事件
  3. 根据配置判断请求是否需要被 Mock
  4. 将符合条件的请求转发到 Mock 服务器
  5. 将 Mock 服务器的响应返回给原始请求

核心文件结构

/src/config/mock/
  ├── registerMockServiceWorker.js  // 注册 Service Worker
  ├── mockConfig.js                 // 基础配置文件
  └── mockConfig.local.js           // 本地环境配置文件
/public/
  └── mockServiceWorker.js          // Service Worker 实现

配置文件详解

mockConfig.js

这是基础配置文件,定义了默认的 Mock 行为:

// 默认配置
const defaultConfig = {
  // 是否启用 mock
  enabled: import.meta.env.MODE === 'dev',

  // mock 服务器地址
  mockServerUrl: '',

  // 需要被拦截转发到 mock 服务器的请求前缀
  apiPrefixes: [],

  // 不需要被 mock 的请求前缀(优先级高于 apiPrefixes)
  excludePrefixes: []
};

mockConfig.local.js

本地环境配置文件,可根据个人需求修改:

export default {
  enabled: false,
  mockServerUrl: 'https://pt-yapi.my4399.com/mock/264',
  apiPrefixes: ['/fnflow'],
  excludePrefixes: ['/api/v1/no-mock']
};

Service Worker 实现

Service Worker (mockServiceWorker.js) 实现了请求拦截与转发的核心逻辑:

globalThis.addEventListener('fetch', event => {
  if (!mockConfig.enabled) {
    return;
  }

  const request = event.request;
  const url = new URL(request.url);

  // 检查是否需要 mock
  const matchedPrefix = mockConfig.apiPrefixes.find(prefix => url.pathname.includes(prefix));
  const hasExcludePrefix = mockConfig.excludePrefixes.some(prefix => url.pathname.includes(prefix));
  const shouldMock = matchedPrefix && !hasExcludePrefix;

  if (!shouldMock) {
    return;
  }

  // 从原始 URL 中提取出以 prefix 开始的部分作为路径
  const prefixIndex = url.href.indexOf(matchedPrefix);
  const mockPath = url.href.slice(prefixIndex);

  // 构建转发到 mock 服务器的 URL
  const mockUrl = mockConfig.mockServerUrl + mockPath;

  // 创建新的请求并转发
  const mockRequest = new Request(mockUrl, {
    method: request.method,
    headers: request.headers,
    body: request.body,
    mode: 'cors',
    credentials: 'include'
  });

  event.respondWith(
    fetch(mockRequest)
      .then(response => response.clone())
      .catch(error => {
        return new Response(
          JSON.stringify({
            error: 'Mock server error',
            message: error.message
          }),
          {
            status: 500,
            headers: {
              'Content-Type': 'application/json'
            }
          }
        );
      })
  );
});

注册 Service Worker

registerMockServiceWorker.js 负责在应用启动时注册 Service Worker:

export async function registerMockServiceWorker() {
  if (!mockConfig.enabled) {
    return;
  }

  if ('serviceWorker' in navigator) {
    try {
      // 将配置转换为 URL 参数
      const configParams = new URLSearchParams({
        config: JSON.stringify(mockConfig)
      }).toString();

      const registration = await navigator.serviceWorker.register(`/mockServiceWorker.js?${configParams}`, {
        scope: '/'
      });

      console.log('Mock Service Worker registered:', registration.scope);
    } catch (error) {
      console.error('Mock Service Worker registration failed:', error);
    }
  }
}

如何使用

1. 在应用入口处注册 Service Worker

import { registerMockServiceWorker } from './config/mock/registerMockServiceWorker';

// 应用初始化时注册
registerMockServiceWorker();

2. 配置 Mock 服务

  1. 复制 mockConfig.local.js 并根据需要修改:
    • enabled: 是否启用 Mock
    • mockServerUrl: Mock 服务器地址(如 YApi、Mock.js 服务等)
    • apiPrefixes: 需要被拦截的 API 前缀
    • excludePrefixes: 不需要被拦截的 API 前缀

3. 开发 Mock 接口

在 Mock 平台(如 YApi)上创建对应的 Mock 接口,确保路径与实际 API 路径一致。

image.png

优势与注意事项

优势

  1. 无侵入性:不需要修改现有代码,通过配置即可启用或禁用
  2. 灵活性高:可以精确控制哪些请求需要 Mock,哪些走真实接口
  3. 开发效率:支持热更新,修改 Mock 数据后立即生效
  4. 团队协作:团队可以共享 Mock 服务,统一数据规范

注意事项

  1. Service Worker 只能在 HTTPS 或 localhost 环境下运行
  2. 首次加载页面后 Service Worker 才会生效
  3. 调试时可通过浏览器的开发者工具查看 Service Worker 状态
  4. 确保 Mock 服务器返回的数据格式与真实 API 一致

扩展思路

  1. 条件 Mock:根据特定条件决定是否 Mock,如请求参数、Header 等
  2. Mock 数据缓存:缓存 Mock 数据以提高性能
  3. Mock 切换:提供 UI 界面动态切换 Mock 状态
  4. 请求记录:记录所有请求,用于调试和测试

总结

通过 Service Worker 实现的 API Mock 方案,我们可以在不修改业务代码的情况下灵活地进行前端开发和测试。这种方案特别适合前后端分离的开发模式,能够有效提高开发效率,减少环境依赖。