proxy.js 3.76 KB
Newer Older
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 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
const { createProxyMiddleware } = require('http-proxy-middleware');
const logger = require('./logger');

const setupProxyFeature = (app, webpackConfig) => {
  if (!Array.isArray(webpackConfig.proxy)) {
    if (Object.prototype.hasOwnProperty.call(webpackConfig.proxy, 'target')) {
      webpackConfig.proxy = [webpackConfig.proxy];
    } else {
      webpackConfig.proxy = Object.keys(webpackConfig.proxy).map(context => {
        let proxyOptions;
        // For backwards compatibility reasons.
        const correctedContext = context
          .replace(/^\*$/, '**')
          .replace(/\/\*$/, '');

        if (typeof webpackConfig.proxy[context] === 'string') {
          proxyOptions = {
            context: correctedContext,
            target: webpackConfig.proxy[context],
          };
        } else {
          proxyOptions = Object.assign({}, webpackConfig.proxy[context]);
          proxyOptions.context = correctedContext;
        }

        proxyOptions.logLevel = proxyOptions.logLevel || 'warn';

        return proxyOptions;
      });
    }
  }

  // eslint-disable-next-line consistent-return
  const getProxyMiddleware = proxyConfig => {
    const context = proxyConfig.context || proxyConfig.path;

    // It is possible to use the `bypass` method without a `target`.
    // However, the proxy middleware has no use in this case, and will fail to instantiate.
    if (proxyConfig.target) {
      return createProxyMiddleware(context, proxyConfig);
    }
  };
  /**
   * Assume a proxy configuration specified as:
   * proxy: [
   *   {
   *     context: ...,
   *     ...options...
   *   },
   *   // or:
   *   function() {
   *     return {
   *       context: ...,
   *       ...options...
   *     };
   *   }
   * ]
   */
  webpackConfig.proxy.forEach(proxyConfigOrCallback => {
    let proxyMiddleware;

    let proxyConfig =
      typeof proxyConfigOrCallback === 'function'
        ? proxyConfigOrCallback()
        : proxyConfigOrCallback;

    proxyMiddleware = getProxyMiddleware(proxyConfig);

    if (proxyConfig.ws) {
      this.websocketProxies.push(proxyMiddleware);
    }

    // eslint-disable-next-line consistent-return
    const handle = (req, res, next) => {
      if (typeof proxyConfigOrCallback === 'function') {
        const newProxyConfig = proxyConfigOrCallback();

        if (newProxyConfig !== proxyConfig) {
          proxyConfig = newProxyConfig;
          proxyMiddleware = getProxyMiddleware(proxyConfig);
        }
      }

      // - Check if we have a bypass function defined
      // - In case the bypass function is defined we'll retrieve the
      // bypassUrl from it otherwise bypassUrl would be null
      const isByPassFuncDefined = typeof proxyConfig.bypass === 'function';
      const bypassUrl = isByPassFuncDefined
        ? proxyConfig.bypass(req, res, proxyConfig)
        : null;

      if (typeof bypassUrl === 'boolean') {
        // skip the proxy
        req.url = null;
        next();
      } else if (typeof bypassUrl === 'string') {
        // byPass to that url
        req.url = bypassUrl;
        next();
      } else if (proxyMiddleware) {
        return proxyMiddleware(req, res, next);
      } else {
        next();
      }
    };

    app.use(handle);
    // Also forward error requests to the proxy so it can handle them.
    app.use((error, req, res, next) => handle(req, res, next));
  });
};

const addProxyMiddleware = app => {
  if (process.env.PROXY) {
    const proxies = process.env.PROXY.split(';');
    // 设置代理
    setupProxyFeature(app, {
      proxy: proxies.map(proxyStr => {
        const mathes = proxyStr.match(/^\s*([/\w]+)\s*:\s*(.+)\s*$/);
        return {
          path: mathes[1],
          target: mathes[2],
          changeOrigin: true,
        };
      }),
    });
  }
};

module.exports = {
  addProxyMiddleware,
};