const fs = require('fs'); const path = require('path'); const axios = require('axios'); /** * 静态 JS 代理/缓存 * * 规则: * - 前端请求:GET /static/boss,header 里带 path,例如: * path: https://static.zhipin.com/fe-zhipin-geek/web/chat-new/v5410/static/js/app.4e199352.js * - 从 URL 中取 pathname:/fe-zhipin-geek/web/chat-new/v5410/static/js/app.4e199352.js * - 去掉开头的 /,中间的 / 全部替换为 _,得到本地文件名: * fe-zhipin-geek_web-chat-new_v5410_static_js_app.4e199352.js * - 在项目根目录下的 js 目录保存/读取该文件:./js/<文件名> * - 如果已存在:直接返回本地文件 * - 如果不存在:从远程 URL 下载,保存后返回 */ module.exports = { 'GET /static/boss': async (ctx) => { // 1. 获取原始 URL(优先从 header,兼容 query/body) const urlStr = ctx.get('path') || ctx.query.path || (ctx.request.body && ctx.request.body.path); if (!urlStr) { ctx.status = 400; ctx.body = { code: 400, message: '缺少 path 参数' }; return; } let urlObj = new URL(urlStr); // 2. 生成本地文件名:去掉开头的 /,中间 / 替换为 _ const remotePath = urlObj.pathname || '/'; const fileName = remotePath .replace(/^\/+/, '') .replace(/\//g, '_'); // 根目录下 js 目录 const jsRootDir = path.join(process.cwd(), 'static/boss'); const localFilePath = path.join(jsRootDir, fileName); // 钩子注入:在 JS 中注入自定义 onMessageArrived 钩子 const injectOnMessageArrivedHook = (buffer) => { try { let js = buffer.toString('utf8'); const needle = 'onMessageArrived:function(e){try{var t=e.payloadBytes,n=S.decode(t);'; if (js.includes(needle)) { const hook = `${needle}if(window.Function&&window.Function.__proto__&&typeof window.Function.__proto__.$onMessageArrived==="function"){try{window.Function.__proto__.$onMessageArrived(n);}catch(e){}}`; js = js.replace(needle, hook); return Buffer.from(js, 'utf8'); } return buffer; } catch (e) { return buffer; } }; // 确保目录存在 if (!fs.existsSync(jsRootDir)) { fs.mkdirSync(jsRootDir, { recursive: true }); } // 3. 如果文件已存在,直接返回本地文件(文件内容已是替换后的,无需再次注入) if (fs.existsSync(localFilePath)) { ctx.type = 'application/javascript; charset=utf-8'; ctx.body = fs.createReadStream(localFilePath); return; } // 4. 文件不存在:从远程下载并保存(带钩子注入) const response = await axios.get(urlStr, { responseType: 'arraybuffer', timeout: 15000, }); if (response.status !== 200) { ctx.status = 502; ctx.body = { code: 502, message: '下载远程 JS 失败' }; return; } const patched = injectOnMessageArrivedHook(Buffer.from(response.data)); fs.writeFileSync(localFilePath, patched); ctx.type = 'application/javascript; charset=utf-8'; ctx.body = patched; }, }