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