UNPKG

env-manage-plugin

Version:

A dev env plugin that integrates an Express server with request proxying capabilities.

203 lines (202 loc) 7.08 kB
import express from "express"; import { createProxyMiddleware } from "http-proxy-middleware"; import setCookieParser from "set-cookie-parser"; import * as libCookie from "cookie"; import { getConfig } from "../utils/ResolveConfig.js"; import { devServerLogger } from "../utils/logger.js"; class PreProxyServer { /** * 判断该端口是否已经有服务存在 * @param port * @returns */ static getAppInsByPort(port) { return this.appMap[port]; } static async create(envId, envRepo, devServerRepo) { if (this.appMap[envId]) { devServerLogger.info(`环境 ${envId} 已经启动`); return null; } const preProxyServer = new PreProxyServer(envId, envRepo, devServerRepo); await preProxyServer.startServer(); PreProxyServer.appMap[envId] = preProxyServer; return preProxyServer; } constructor(envId, envRepo, devServerRepo, app = express()) { this.envId = envId; this.envRepo = envRepo; this.devServerRepo = devServerRepo; this.app = app; app.use(this.createPreProxyMiddleware()); } /** * * @returns 获取绑定的环境信息 */ getEnvItem() { const envItem = this.envRepo.findOneById(this.envId); return envItem; } /** * 获取绑定的服务器详情 */ getDevServer() { } /** * 当前 代理的 cookie 后缀 */ get cookieSuffix() { const envItem = this.getEnvItem(); return `-${envItem?.port}-${PreProxyServer.configCookieSuffix}`; } /** * 配置的 cookie 后缀 */ static get configCookieSuffix() { return `${getConfig().cookieSuffix}`; } /** * 生成代理中间件 * @returns */ createPreProxyMiddleware() { // 前置转发:将请求转发到 开发服务器 return createProxyMiddleware({ ws: true, changeOrigin: true, router: () => { // 查询环境信息 const envItem = this.getEnvItem(); // 根据环境信息查询绑定的 devServer 地址 const devServerConfig = this.devServerRepo.findOneById({ id: envItem?.devServerId ?? "", }); // 转发到 devServer return `${devServerConfig?.devServerUrl}`; }, on: { proxyReq: (proxyReq, req) => { const envItem = this.getEnvItem(); const target = `${envItem?.apiBaseUrl}`; proxyReq.setHeader("x-api-server", `${target}`); this._rewrieCookieOnProxyReq(proxyReq, req); }, proxyRes: (proxyRes) => { this._rewriteSetCookieOnProxyRes(proxyRes); }, proxyReqWs: (proxyReq) => { const envItem = this.getEnvItem(); const target = `${envItem?.apiBaseUrl}`; proxyReq.setHeader("x-api-server", `${target}`); }, }, }); } /** * 代理的时候如果收到了 setcookie 请求 * 给 每一个 setcookie 追加保存一个 代理cookie * @param proxyRes */ _rewriteSetCookieOnProxyRes(proxyRes) { const envItem = this.getEnvItem(); const setCookie = proxyRes.headers["set-cookie"]; if (envItem && setCookie) { const setCookies = setCookieParser.parse(setCookie); const proxyCookie = setCookies.map((item) => { const cookie = { ...item, name: `${item.name}${this.cookieSuffix}`, }; return libCookie.serialize(cookie.name, cookie.value, cookie); }); setCookie.push(...proxyCookie); } } /** * 代理 转发的时候,将对应端口的cookie 重写回去 */ _rewrieCookieOnProxyReq(proxyReq, req) { const envItem = this.getEnvItem(); if (envItem && req.headers.cookie) { const cookie = libCookie.parse(req.headers.cookie || ""); const newCookies = []; Object.keys(cookie).forEach((item) => { if (item.endsWith(PreProxyServer.configCookieSuffix)) { return; } let cookieName = `${item}${this.cookieSuffix}`; if (!cookie[cookieName]) { cookieName = item; } newCookies.push(libCookie.serialize(item, cookie[cookieName] || "")); }); proxyReq.setHeader("cookie", newCookies.join(";")); } } /** * 启动服务 * @param envItem * @returns */ async startServer() { const { port } = this.getEnvItem(); if (PreProxyServer.appMap[this.envId]) { devServerLogger.info(`环境 ${this.envId} 已经启动`); return; } this.server = await new Promise((resolve, reject) => { const server = this.app.listen(port, () => { devServerLogger.info(`Server is running on http://localhost:${port}`); // 更新状态 resolve(server); }); server.on("error", (err) => { console.error(`端口 ${port} 启动失败:`, err.message); reject(err); }); }); // 保存所有活动的 socket 连接 this.sockets = new Set(); this.server.on("connection", (socket) => { this.sockets.add(socket); // 保存 socket socket.setTimeout(300000); // 设置超时时间为 5 分钟 socket.on("timeout", () => { socket.destroy(); this.sockets.delete(socket); }); // 监听 socket 关闭事件 socket.on("close", () => { this.sockets.delete(socket); // 从集合中移除已关闭的 socket }); }); } static stopServer(id) { return new Promise((resolve) => { if (!this.getAppInsByPort(id)) { devServerLogger.info(`端口 【${id}】 未启动,无需停止!`); resolve(1); return; } for (const socket of this.appMap[id].sockets) { socket.destroy(); } this.appMap[id].server.close((err) => { // 停止服务更新状态 if (err) { console.error("服务器关闭失败:", err); resolve(0); } else { delete this.appMap[id]; devServerLogger.info({ id }, `Server on port ${id} 已关闭`); resolve(1); } }); }); } } /** * 保存启动的环境实例 */ PreProxyServer.appMap = {}; export default PreProxyServer;