当前位置: 代码迷 >> 综合 >> koa2 请求转发实现
  详细解决方案

koa2 请求转发实现

热度:76   发布时间:2023-12-26 08:43:05.0

最近在学习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参数会出现乱码,像下面这样:
在这里插入图片描述
等实在代码洁癖犯了想想换种实现方法