Express http-proxy-middleware 保存代理接口数据到本地

const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const fs = require('fs');
const JSONStream = require('JSONStream');

const app = express();
const port = 10086;

const targetUrl = 'https://lgkp-uat.ihanchen.com/';
const tartUrlKey = 'lgkp-uat';
const MOCK = false;
const MOCK_FAIL_DEFAULT = {
  code: -1,
  msg: '接口调用失败',
  success: false,
}
const ignoreParamKey = ['code', 'phoneCode', 'third_id', 'clickId', 'startTime', 'endTime']


function readFileStreamAsync(filePath, apiKey) {
  return new Promise((resolve, reject) => {
    const fileReadStream = fs.createReadStream(filePath);
    const parser = JSONStream.parse("0.data");
    fileReadStream.pipe(parser)

    parser.on('data', data => {
      // console.log('fileReadStream', data);
      if (data[apiKey]) {
        resolve(data[apiKey])
      } else {
        reject(undefined)
      }
    })

    parser.on('error', err => {
      console.log(err)
      reject(err)
    })
  })
}

function getBodyFromReq(req) {
  return new Promise((resolve, reject) => {
    if (req.method === 'POST' || req.method === 'PUT') {
      let bodyData = '';
      req.on('data', chunk => {
        bodyData += chunk.toString();
      });
      req.on('end', () => {
        // console.log('Body data:', bodyData); // 字符串类型
        resolve(bodyData)
      });
    } else {
      resolve('{}');
    }
  });
}

function getBodyFromRes(proxyRes) {
  return new Promise((resolve, reject) => {
    console.log('getBodyFromRes init');
    let bodyData = [];
    proxyRes.on('data', chunk => {
      // console.log('on data', Buffer.concat([chunk]).toString());
      bodyData.push(chunk);
    });
    proxyRes.on('end', () => {
      bodyData = Buffer.concat(bodyData).toString();
      // console.log('on end:', bodyData); // 字符串类型
      try {
        const body = JSON.parse(bodyData)
        resolve(body);
      } catch (e) {
        console.log('出错了啊')
        reject(e)
      }
    });
  });
}


app.use('/', createProxyMiddleware({
  target: targetUrl,
  changeOrigin: true,
  on: {
    proxyReq: async (proxyReq, req, res) => {
      /* handle proxyReq */
      // console.log('proxyReq, req, res', {proxyReq, req, res})
      let reqBody = await getBodyFromReq(req);
      // console.log('delete ignoreParamKey before', reqBody);
      if (ignoreParamKey && ignoreParamKey.length) {
        const reqBodyObj = JSON.parse(reqBody);
        for(let key in reqBodyObj) {
          if (ignoreParamKey.includes(key)) {
            delete reqBodyObj[key];
          }
        }
        reqBody = JSON.stringify(reqBodyObj);
      }
      // console.log('delete ignoreParamKey after', reqBody);
      req.reqBody = reqBody;
      const { method, path, params, query } = req;
      if (ignoreParamKey && ignoreParamKey.length) {
        for(let key in params) {
          if (ignoreParamKey.includes(key)) {
            delete params[key];
          }
        }
      }
      const fileName = `${JSON.stringify(params)} ${JSON.stringify(query)} ${reqBody.slice(0, 50)}`;
      const apiKey = `${JSON.stringify(params)} ${JSON.stringify(query)} ${reqBody}`;
      const dirPath = `./src/buffers/${tartUrlKey}/${method}/${encodeURIComponent(path)}`;
      const filePath = `${dirPath}/${encodeURIComponent(fileName)}.json`;
      if (!fs.existsSync(`./src/buffers/${tartUrlKey}`)) {
        fs.mkdirSync(`./src/buffers/${tartUrlKey}`);
      }
      if (!fs.existsSync(`./src/buffers/${tartUrlKey}/${method}`)) {
        fs.mkdirSync(`./src/buffers/${tartUrlKey}/${method}`);
      }
      if (!fs.existsSync(dirPath)) {
        fs.mkdirSync(dirPath);
      }
      if (!fs.existsSync(filePath)) {
        fs.writeFileSync(filePath, JSON.stringify([{data: {}}]))
      }

      if (MOCK) {
        try {
          const dataMock = await readFileStreamAsync(filePath, apiKey);
          // 解析原始响应体
          let parsedData = dataMock;
          
          // 设置新的响应头并发送修改后的数据
          // res.setHeader('Content-Length', JSON.stringify(parsedData).length);
          res.json(parsedData);
        } catch (e) {
          console.trace(e);
          res.json(MOCK_FAIL_DEFAULT);
          // res.end("my response to cli");
        }
      }
    },
    proxyRes: async (proxyRes, req, res) => {
      /* handle proxyRes */
      // console.log('proxyRes, req, res', {proxyRes, req, res})
      if (!MOCK) {
        try {
          const reqBody =  req.reqBody || '{}';
          // console.log('reqBody:', reqBody);
          const { method, path, params, query } = req;
          if (ignoreParamKey && ignoreParamKey.length) {
            for(let key in params) {
              if (ignoreParamKey.includes(key)) {
                delete params[key];
              }
            }
          }
          // console.log('params, query', {params, query});
          const fileName = `${JSON.stringify(params)} ${JSON.stringify(query)} ${reqBody.slice(0, 50)}`;
          const apiKey = `${JSON.stringify(params)} ${JSON.stringify(query)} ${reqBody}`;
          const dirPath = `./src/buffers/${tartUrlKey}/${method}/${encodeURIComponent(path)}`;
          const filePath = `${dirPath}/${encodeURIComponent(fileName)}.json`;
  
          // console.log('开始解析返回数据' + path);
          let respBody = await getBodyFromRes(proxyRes).catch(e => {
            console.trace(e);
          });
          // console.log('结束解析返回数据: ' + respBody);
  
          if (respBody && respBody.success) {
            // console.log("res body from proxied server:", body);
            const fileWriteStream = fs.createWriteStream(filePath);
            const stringify = JSONStream.stringify();
    
            stringify.pipe(fileWriteStream);
            const data = {};
            data[apiKey] = respBody;
            stringify.write({
              data,
            });
            stringify.end();
          }
          res.end("my response to cli");
        } catch(e) {
          console.trace(e);
          console.log("err req from proxied server:", {
            method, path, params, query
          });
        }
      }
    },
    error: (err, req, res) => {
      /* handle error */
    },
  },
}));

app.listen(port, () => {
  console.log(`Proxy server is running on port ${port}`);
});

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值