Files
UserclassService/work/cache-proxy.js
T
2026-08-20 21:56:45 +08:00

114 lines
4.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 本地缓存查看代理(仅开发/排查用,不要部署到生产)
*
* 解决的问题:本地双击打开 work-view.html 时,浏览器是 file:// 跨域访问远程
* http://base.yunhaixingtong.com,出于安全策略【不会】把 CAS 登录 Cookie 带过去,
* 导致每个请求都被 CAS 拦截返回 302。而浏览器又禁止 JS 用 fetch 设置 Cookie 请求头。
*
* 做法:页面把“从 DevTools 复制的登录 Cookie”放进自定义头 x-auth-cookie 发给本代理,
* 本代理在服务端把它注入成真实 Cookie 头,再转发到远程。远程因此认为是已登录的超管会话。
*
* 用法:
* 1) 确认本机装有 Node(>=14)。
* 2) 在本文件目录运行: node work/cache-proxy.js
* 3) 浏览器打开 work-view.html,在“Cookie”框粘贴完整 Cookie 串(见下方说明)。
* 4) 页面 SERVER 默认 http://localhost:8899 即指向本代理。
*
* 如何复制 Cookie:浏览器 DevTools → Application → Cookies → 选中 base.yunhaixingtong.com
* 全选复制为 “name=value; name2=value2; ...” 形式(建议把该域下所有 Cookie 都带上,
* 通常含 JSESSIONID / CASTGC 等,缺一不可)。
*/
const http = require('http');
const https = require('https');
const { URL } = require('url');
const TARGET_BASE = 'http://192.168.10.166:8086';
const PORT = 8899;
const server = http.createServer((req, res) => {
// 允许本地 file:// 页面跨域调用本代理
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET,POST,OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type,x-auth-cookie');
if (req.method === 'OPTIONS') {
res.writeHead(204);
return res.end();
}
// 登录态来源:优先页面/脚本发的 x-auth-cookie 头;也支持浏览器直接敲地址时带 ?cookie= 参数
const reqUrl = new URL(req.url, 'http://localhost');
const cookie = req.headers['x-auth-cookie'] || reqUrl.searchParams.get('cookie') || '';
if (!cookie) {
res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });
return res.end(
JSON.stringify({
msg: '缺少登录态:页面请在“Cookie”框粘贴;或浏览器直接访问时附加 ?cookie=NAME=VALUE;NAME2=VALUE2',
})
);
}
// 从转发给远程的 URL 中去掉本地专用的 cookie 参数
reqUrl.searchParams.delete('cookie');
const target = new URL(TARGET_BASE + reqUrl.pathname + reqUrl.search);
const isHttps = target.protocol === 'https:';
const options = {
method: req.method,
hostname: target.hostname,
port: target.port || (isHttps ? 443 : 80),
path: target.pathname + target.search,
headers: {
Cookie: cookie,
Accept: 'application/json',
'Accept-Encoding': 'identity',
'User-Agent': req.headers['user-agent'] || 'cache-proxy',
},
};
const transport = isHttps ? https : http;
const proxyReq = transport.request(options, (proxyRes) => {
// 远程未部署缓存接口:明确提示,避免把 Spring 404 白页甩给页面
if (proxyRes.statusCode === 404) {
res.writeHead(404, { 'Content-Type': 'application/json; charset=utf-8' });
res.end(
JSON.stringify({
msg:
'远程返回 404:该实例未部署缓存接口 /api/cache/*(请部署含 CacheController 的新 jar 到 ' +
target.host +
')',
})
);
return;
}
// 远程要求登录(CAS 拦截)或权限不足:回一封干净的 JSON 错误,避免把登录页 HTML 抛给页面
if ([301, 302, 401, 403].includes(proxyRes.statusCode)) {
let buf = '';
proxyRes.on('data', (c) => (buf += c));
proxyRes.on('end', () => {
res.writeHead(401, { 'Content-Type': 'application/json; charset=utf-8' });
res.end(
JSON.stringify({
msg: '远程返回 ' + proxyRes.statusCode + ':Cookie 可能已失效或未登录,请重新从 DevTools 复制完整 Cookie',
})
);
});
return;
}
res.writeHead(proxyRes.statusCode, {
'Content-Type': proxyRes.headers['content-type'] || 'application/json; charset=utf-8',
});
proxyRes.pipe(res);
});
proxyReq.on('error', (err) => {
res.writeHead(502, { 'Content-Type': 'application/json; charset=utf-8' });
res.end(JSON.stringify({ msg: '代理转发失败:' + err.message }));
});
req.pipe(proxyReq);
});
server.listen(PORT, () => {
console.log('[cache-proxy] 监听 http://localhost:' + PORT + ' -> ' + TARGET_BASE);
});