vite-plugin-mock icon indicating copy to clipboard operation
vite-plugin-mock copied to clipboard

在生产环境下,使用fetch的mock请求不生效

Open EralChen opened this issue 4 years ago • 2 comments

关于vite.config的配置:

viteMockServe({
      mockPath: 'mock',
      ignore: /^\_/,
      localEnabled: command === 'serve',
      prodEnabled: command !== 'serve',
      injectCode: `
        import { setupProdMockServer } from '../mock/_createProductionServer';

        setupProdMockServer();
      `,
    }),
// ../mock/_createProductionServer
import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer'

import ElOptions from './el-options'

export function setupProdMockServer () {
  createProdMockServer([...ElOptions])
}
// ./el-opitons
import { MockMethod } from 'vite-plugin-mock'
import ResWrap from './_utils/ResponseWrap'
export default [
  {
    url: '/mock/cascader-options',
    method: 'get',
    response: () => {
      return new ResWrap({
        type: 'success',
        data: [data]// 省略data
      })
    },
  },
] as MockMethod[] 

在开发环境下,正常请求到数据: image

在生产环境下,请求404: image

相关依赖: "vite": "^2.5.6", "vite-plugin-mock": "^2.9.6",

非常感谢您的阅读,我不知道是否是我忽略了什么,导致我上述问题。如果是这样的,希望您能指点一二。

EralChen avatar Sep 26 '21 04:09 EralChen

目前我是这么解决的 创建createFetchSever.ts文件

import Mock from 'mockjs'
/**
 * @param mockList
 */
export function createFetchSever (mockList: any[]) {
  if (!window['originFetch']) {
    window['originFetch'] = window.fetch
    window.fetch = function (fetchUrl: string, init: RequestInit) {
      const currentMock = mockList.find(mi => fetchUrl.includes(mi.url))
      if (currentMock) {
        const result = createFetchReturn(currentMock, init)
        return result
      } else {
        return window['originFetch'](fetchUrl, init)
      }
    }
  }
}

function __param2Obj__(url: string) {
  const search = url.split('?')[1]
  if (!search) {
    return {}
  }
  return JSON.parse(
    '{"' +
    decodeURIComponent(search)
      .replace(/"/g, '\\"')
      .replace(/&/g, '","')
      .replace(/=/g, '":"')
      .replace(/\+/g, ' ') +
    '"}',
  )
}


function __Fetch2ExpressReqWrapper__(handle: (d: any) => any) {
  return function (options: any) {
    let result = null
    if (typeof handle === 'function') {
      const { body, method, url, headers } = options

      let b = body
      try {
        b = JSON.parse(body)
      } catch {}
      result = handle({
        method,
        body: b,
        query: __param2Obj__(url),
        headers,
      })
    } else {
      result = handle
    }

    return Mock.mock(result)
  }
}

function setupTimeOut (timeout = 0) {
  timeout &&
  Mock.setup({
    timeout,
  })
}

function createFetchReturn (mock: Recordable, init: RequestInit) {
  const { timeout, response } = mock
  setupTimeOut(timeout)
  const mockFn = __Fetch2ExpressReqWrapper__(response)
  const data = mockFn(init)
  const result = {
    ok: true,
    status: 200,
    clone: () => {
      return result
    },
    text () {
      return Promise.resolve(data);
    },
    json () {
      return Promise.resolve(data);
    }
  }
  return result
}

在原有提供的setupProdMockSever中添加

import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer'


import list from './modules/list'

import { createFetchSever } from 'createFetchSever'

const modules = [...list]

export function setupProdMockServer() {
  createProdMockServer(modules)
  // 添加这一行
  createFetchSever(modules)
}

PS: 我是用的umi-request,能解决生产上fetch请求不支持的问题。其它的fetch库,比如ky之类的我没有测试过。 mockjs本身没有重写fetch方法,只重写的XHRHttp。所以原理 就是自己重写一下Fetch方法,解析格式保持跟这个插件一致就行了

JobinJia avatar Nov 30 '21 15:11 JobinJia

说实话这个库应该默认支持 XHR 和 fetch,fetch 的 API 更加现代化,所以我基本不用 XHR,除非涉及到上传下载进度的场景。因此我参考了 mock,自己实现了:vite-plugin-fake-server,默认可以拦截两种请求。

除此之外还支持以下特性:

  1. 支持 TypeScript
  2. API 的格式兼容 vite-plugin-mock
  3. 一键配置,生产环境直接打开 enableProd 就生效了
  4. 全局设置 headers
  5. 全局设置 timeout
  6. 等等

condorheroblog avatar Oct 17 '23 10:10 condorheroblog