最近在学习vue3+nestjs,打算用这两个做一个博客(页面仔都喜欢做博客网站,我也一样!!)。为了节约时间,提高效率,博客网站的管理后台、数据统计页面我打算用之前做的基于vue2+kao2的项目。
那么这样就出现了一个问题:后台管理页面有两个服务,一个是之前做好的基于koa2的,一个是基于新东西nestjs的。这样就需要做请求服务的代理将不同的服务代理到对应的服务器上。

对于代理,有很多办法,前端配置代理,后端请求转发、网关处理等等。最后我选择了后端请求转发来处理。这样对原先的代码改动最少。

代码

直接上代码,屁话后面说

// 中间件 /middleware/httpProxy.js
const axios = require('axios');
const qs = require('qs');

module.exports = (opts = {}) => {
  return (ctx, next) => {
    if (!ctx.httpProxy) {
      proxy(ctx, opts);
    }

    return next();
  };
};

function proxy(ctx, opts) {
  ctx.httpProxy = (params = {}) => {
    params = Object.assign({}, { host: opts.apiHost || '' }, params);

    let reqParams = Object.assign({}, params, formatReqParams(ctx, params));
    if (reqParams.method.toUpperCase() !== 'GET') {
      reqParams.data = params.data || ctx.request.body;
    }
    // application/x-www-form-urlencoded形式转发参数乱码修改
    if (qs.stringify(ctx.request.body)) {
      reqParams = { ...reqParams, data: qs.stringify(ctx.request.body) };
    }

    delete reqParams.headers.host;
    return axios(reqParams)
      .then(res => {
        const { data, headers } = res;

        setResCookies(ctx, headers);

        return data;
      })
      .catch(err => {
        // console.log(err)
        return err;
      });
  };
}
function setResCookies(ctx, headers) {
  const resCookies = headers['set-cookie'];

  if (!headers || !resCookies || !resCookies.length || resCookies.length <= 0 || !resCookies[0]) {
    return;
  }

  ctx.res._headers = ctx.res._headers || {};
  ctx.res._headerNames = ctx.res._headerNames || {};

  ctx.res._headers['set-cookie'] = ctx.res._headers['set-cookie'] || [];
  ctx.res._headers['set-cookie'] =
    ctx.res._headers['set-cookie'].concat && ctx.res._headers['set-cookie'].concat(resCookies);

  ctx.res._headerNames['set-cookie'] = 'set-cookie';
}

/**
 * @param  {} ctx koa当前执行上下文
 * @param  {} params 请求参数
 */
function formatReqParams(ctx, params) {
  let { url, method, headers, protocol } = ctx;
  const { host } = params;
  const hasProtocol = /(http|s):\/\//;

  url = params.url || url;
  method = params.method || method;
  protocol = hasProtocol.test(url) ? url.split(':')[0] : params.protocol || protocol;

  url = `${protocol}://${host}${url}`;
  delete params.host;

  return { url, method, protocol, headers };
}



// 注册及使用 app.js
const httpProxy = require('./middleware/httpProxy');
// apiHost即是你要转发请求到后端的host,其他的参数可以参考axioshttps://github.com/axios/axios
// 请求转发中间件,暂时只支持转发到另一个地址
// TODO: 支持多转发
app.use(
  httpProxy({
    apiHost: 'localhost:5000' // 全局端口
  })
);

// 在需要使用的地方调用中间件
// http://xxx:4000/nest/xx的请求会转发到http://xxx:3000/nest/xx
if (url.startsWith('/nest')) {
  const data = await ctx.httpProxy({
    host: 'localhost:3000' // 多代理,nest地址代理到localhost:3000
  });
  // 这里可以做一些请求之后需要处理的事情
  ctx.body = data;
}

使用说明及配置项

功能实现用到的依赖就一个axios,也没做别的魔改,所以配置参看axios

单转发

如果路由不做其他操作,只是简单的IP地址的转发

// 中间件注册
app.use(
  httpProxy({
    apiHost: 'localhost:5000' // 全局端口
  })
);

// 使用
if (url.startsWith('/nest')) { // 路径匹配
  const data = await ctx.httpProxy();
  // 这里可以做一些请求之后需要处理的事情
  ctx.body = data;
}

如果还有对接口地址进行修改的话

// 使用

if (url.startsWith('/test')) {
  // 对url的处理
  // 。。。
  const data = await ctx.httpProxy({
  	// url: '/nest/schedule'
    url: 'newUrl'
  });
  // 这里可以做一些请求之后需要处理的事情
  ctx.body = data;
}

多转发

A转发newA,B转发newB。。。

// 中间件注册
app.use(httpProxy());

// 使用
if (url.startsWith('/nest')) {
  const data = await ctx.httpProxy({
     host: 'localhost:5000' // 多代理,nest地址代理到localhost:3000
   });
   // 这里可以做一些请求之后需要处理的事情
   ctx.body = data;
 } else if (url.startsWith('/test')) {
   const data = await ctx.httpProxy({
     host: 'localhost:3000', // 多代理,nest地址代理到localhost:3000
   });
   // 这里可以做一些请求之后需要处理的事情
   ctx.body = data;
}

还有一个代理的中间件:http-proxy-middleware。但是看介绍好像只能在express里用,koa没有案例提示。

这样就可以在任何地方里转发请求,比如鉴权之后,或者是之前写好的项目的某个地方,从而实现服务的扩展。对原来的服务改动的也少。

效果

koa服务在本地的4000端口,nestjs服务在3000端口

直接访问3000端口:
在这里插入图片描述
访问4000端口,进行端口转发
在这里插入图片描述
修改url后再转发
在这里插入图片描述

在这里插入图片描述

不足

这只是简单的使用axios进行请求转发,不是真正的代理
这就导致会出现一些意想不到的错误,就比如传递body参数的时候由于不是xxx=xxx&xxx=xxx形式,所以第二次接收body参数会出现乱码,像下面这样:
在这里插入图片描述
等实在代码洁癖犯了想想换种实现方法

Logo

前往低代码交流专区

更多推荐