• umi/max如何给请求增加公共header


    直接上代码
    在这里插入图片描述
    根据 umi官网 介绍可知,umi/max仅提供一种运行时配置的方法。
    如果是搭配typescript开发的话,最好使用@umi/max提供的RequestConfig类型进行字段控制。

    因为是在app.ts中添加的配置,但是并不知道该配置是在何时何地如何被使用的,所以去翻阅了一下umijs/plugin-request源码

    看到index.ts文件后,得到了启发:

    import { IApi } from 'umi-types';
    import { join, dirname } from 'path';
    import assert from 'assert';
    import { readFileSync } from 'fs';
    
    export interface RequestOptions {
      dataField?: string;
    }
    
    export default function(api: IApi, options: RequestOptions) {
      api.addRuntimePluginKey('request');
    
      const { dataField = 'data' } = options || {};
      const source = join(__dirname, '..', 'src', 'request.ts');
      const requestTemplate = readFileSync(source, 'utf-8');
      const namespace = 'plugin-request';
      assert(/^[a-zA-Z]*$/.test(dataField), 'dataField should match /^[a-zA-Z]*$/');
    
      api.onGenerateFiles(() => {
        try {
          // Write .umi/plugin-request/request.ts
          let formatResultStr;
          if (dataField === '') {
            formatResultStr = 'formatResult: result => result';
          } else {
            formatResultStr = `formatResult: result => result?.${dataField}`;
          }
          api.writeTmpFile(
            `${namespace}/request.ts`,
            requestTemplate
              .replace(/\/\*FRS\*\/(.+)\/\*FRE\*\//, formatResultStr)
              .replace(/\['data'\]/g, dataField ? `['${dataField}']` : '')
              .replace(/data: T;/, dataField ? `${dataField}: T;` : '')
              .replace(
                /umi-request/g,
                api.winPath(dirname(require.resolve('umi-request/package'))),
              )
              .replace(
                /@ahooksjs\/use-request/g,
                api.winPath(dirname(require.resolve('@ahooksjs/use-request/package'))),
              ),
          );
        } catch (e) {
          api.log.error(e);
        }
      });
    
    	// 这里,他去添加了Umi导出的配置
    	// 看代码,猜测路径为: .umi/plugin-request/request.ts
    	
      /**
       * umi 允许插件添加需要 umi 额外导出的内容。
       * 流程是这样的,umi 脚本执行的时候,触发 onGenerateFiles hook 生成临时文件。
       * umi 预设的插件集中有个叫做 umiExports 的插件,
       * 该插件会触发 addUmiExports hook,执行所有插件的该方法,
       * 获得插件中指定的额外导出内容,将这些内容放到临时文件中。
       */
      api.addUmiExports([
        {
          exportAll: true,
          source: api.winPath(join(api.paths.absTmpDirPath, namespace, 'request')),
        },
      ]);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    找到了找到了,在./src/.umi/plugin-request/request.ts中找到了答案:

    // .umi/plugin-request/request.ts
    let config: RequestConfig;
    const getConfig = (): RequestConfig => {
      if (config) return config;
      config = getPluginManager().applyPlugins({
        key: 'request',
        type: ApplyPluginsType.modify,
        initialValue: {},
      });
      return config;
    };
    
    // .umi/core/plugin.ts
    import * as Plugin_0 from 'C:/workspace/psq_system/src/app.ts';
    export function getPlugins() {
      return [
        {
          // Plugin_0就是{antd:{}, layout:{}, request: {}}
          apply: __defaultExport(Plugin_0),
          // 这里这里!
          path: process.env.NODE_ENV === 'production' ? void 0 : 'xxx/src/app.ts',
        },
        // ....
      ];
    }
    
    // 这里就是上面用到的keys,也就是app.ts中可以设置的内容
    export function getValidKeys() {
      return ['patchRoutes','patchClientRoutes','modifyContextOpts','modifyClientRenderOpts','rootContainer','innerProvider','i18nProvider','accessProvider','dataflowProvider','outerProvider','render','onRouteChange','antd','getInitialState','layout','qiankun','request',];
    }
    
    let pluginManager = null;
    
    export function createPluginManager() {
      pluginManager = PluginManager.create({
        plugins: getPlugins(),
        validKeys: getValidKeys(),
      });
      
      return pluginManager;
    }
    
    export function getPluginManager() {
      return pluginManager;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    通过上面的代码,我们可以了解.umi/plugin-request/request.ts中的config是如何生成的。

    1. .umi/plugin-request/request.ts 就是umi运行时读取的配置项
    2. umi在注册plugins的时候第一个就是读取app.ts的配置,赋值给Plugin_0
    3. Plugin_0就是{ antd: {}, layout: {}, request: { }, .... }
    4. { apply: Plugin_0, path: "./src/app.ts" } 作为参数plugins的其中一个,用来创建umi的PluginManager
    5. 创建时会遍历plugins,以第一个举例,拿到他的apply,也就是Plugin_0,遍历对象,拿到key,放入pluginManager的hooks中。
    6. getPluginManager().applyPlugins({})就是对某个hooks的扩展
    7. 而.umi/plugin-request/request.ts中的config就是pluginManager.hooks.request

    最后再来看一下.umi/plugin-request/request.ts中对axios的实例化,看一下config的使用

    const request: IRequest = (url: string, opts: any = { method: 'GET' }) => {
      // 这里需要注意!
      const requestInstance = getRequestInstance();
      // 这里的config就是获取到的pluginManage中的hooks.request
      const config = getConfig();
      requestInstance = axios.create(config);
      // 这里就是对app.ts中request的使用
      config?.requestInterceptors?.forEach((interceptor) => {
        if(interceptor instanceof Array){
          requestInstance.interceptors.request.use((config) => {
            const { url } = config;
            if(interceptor[0].length === 2){
              const { url: newUrl, options } = interceptor[0](url, config);
              return { ...options, url: newUrl };
            }
            return interceptor[0](config);
          }, interceptor[1]);
        } else {
          requestInstance.interceptors.request.use((config) => {
            const { url } = config;
            if(interceptor.length === 2){
              const { url: newUrl, options } = interceptor(url, config);
              return { ...options, url: newUrl };
            }
            return interceptor(config);
          })
        }
      });
      // ....其他的暂时不重要
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    至此,我终于理顺了app.ts中配置项request是如何使用的了!
    大功告成,理了将近5个小时,还是自己太菜了,应该直接去看plugin-request包的,结果先去看了umi中对app.ts的使用,期间又发现对@babel的parse,traverse,types包一脸懵逼,又去稍微了解了一下,花了三个小时,,
    最后看plugin-request也才看了一个多小时。以后要对@babel的包也要了解一下了,前端的知识真是太多了。。

  • 相关阅读:
    gRPC-GateWay Swagger 实战
    深度学习技巧应用28-强化学习的原理介绍与运用技巧实践
    物联网运维-前端设备运维管理设计及解决方案
    MySQL夺命10问,你能坚持到第几问?
    deepstream python yolov5使用记录
    SpringSecuity和Shiro区别
    oak深度相机入门教程-识别眼睛的凝视方向
    2023/9/19 -- C++/QT
    qt 虚拟键盘中的几个瑕疵
    Boot 中bean配置覆盖
  • 原文地址:https://blog.csdn.net/qq_28992047/article/details/132721883