暂存
This commit is contained in:
parent
c92f817d66
commit
6b5eec89ed
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
port: 3005,
|
port: 3005,
|
||||||
api: {
|
api: {
|
||||||
host: 'localhost:4000', // 后台代理
|
host: 'localhost:4002', // 后台代理
|
||||||
path: '/api/router',
|
path: '/api/router',
|
||||||
},
|
},
|
||||||
allowedOrigins: ['localhost', 'xiongxiao.me', 'zxj.im'],
|
allowedOrigins: ['localhost', 'xiongxiao.me', 'zxj.im'],
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
"@rollup/plugin-json": "^6.1.0",
|
"@rollup/plugin-json": "^6.1.0",
|
||||||
"@rollup/plugin-node-resolve": "^15.3.0",
|
"@rollup/plugin-node-resolve": "^15.3.0",
|
||||||
"@rollup/plugin-typescript": "^12.1.0",
|
"@rollup/plugin-typescript": "^12.1.0",
|
||||||
|
"@types/http-proxy": "^1.17.15",
|
||||||
"@types/node": "^22.7.5",
|
"@types/node": "^22.7.5",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"nodemon": "^3.1.7",
|
"nodemon": "^3.1.7",
|
||||||
@ -28,9 +29,10 @@
|
|||||||
"typescript": "^5.6.3"
|
"typescript": "^5.6.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@abearxiong/router": "0.0.1-alpha.40",
|
"@abearxiong/router": "0.0.1-alpha.43",
|
||||||
"@abearxiong/use-config": "^0.0.2",
|
"@abearxiong/use-config": "^0.0.2",
|
||||||
"@abearxiong/use-file-store": "^0.0.1",
|
"@abearxiong/use-file-store": "^0.0.1",
|
||||||
|
"http-proxy": "^1.18.1",
|
||||||
"ioredis": "^5.4.1",
|
"ioredis": "^5.4.1",
|
||||||
"nanoid": "^5.0.7"
|
"nanoid": "^5.0.7"
|
||||||
},
|
},
|
||||||
|
67
pnpm-lock.yaml
generated
67
pnpm-lock.yaml
generated
@ -11,6 +11,9 @@ importers:
|
|||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@abearxiong/router':
|
||||||
|
specifier: 0.0.1-alpha.43
|
||||||
|
version: 0.0.1-alpha.43
|
||||||
'@abearxiong/use-config':
|
'@abearxiong/use-config':
|
||||||
specifier: ^0.0.2
|
specifier: ^0.0.2
|
||||||
version: 0.0.2
|
version: 0.0.2
|
||||||
@ -60,6 +63,9 @@ importers:
|
|||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
|
'@abearxiong/router@0.0.1-alpha.43':
|
||||||
|
resolution: {integrity: sha512-umwi4T5s54Zb8ItseGw3uB7PDG8BqnHyAughlXH2dhub4f49fO+rwR+Zth7scUONkmc21Z27/lPgLBHXrYOkYw==, tarball: https://npm.pkg.github.com/download/@abearxiong/router/0.0.1-alpha.43/287c6e2597b36c5e3ed351b473e38f468b5f49ea}
|
||||||
|
|
||||||
'@abearxiong/use-config@0.0.2':
|
'@abearxiong/use-config@0.0.2':
|
||||||
resolution: {integrity: sha512-IBOmeP46ykbDlkplFS65UsAHjyPDKnvS2oqbkpLWhbSwDbF5zhBnD4ibsFZKPCyc3lMlPeRqYva4x6puX3E/qQ==, tarball: https://npm.pkg.github.com/download/@abearxiong/use-config/0.0.2/59fbeec8c8e086ec48e55024fe39020b079e6fa5}
|
resolution: {integrity: sha512-IBOmeP46ykbDlkplFS65UsAHjyPDKnvS2oqbkpLWhbSwDbF5zhBnD4ibsFZKPCyc3lMlPeRqYva4x6puX3E/qQ==, tarball: https://npm.pkg.github.com/download/@abearxiong/use-config/0.0.2/59fbeec8c8e086ec48e55024fe39020b079e6fa5}
|
||||||
|
|
||||||
@ -231,6 +237,9 @@ packages:
|
|||||||
'@types/estree@1.0.6':
|
'@types/estree@1.0.6':
|
||||||
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
|
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
|
||||||
|
|
||||||
|
'@types/http-proxy@1.17.15':
|
||||||
|
resolution: {integrity: sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==}
|
||||||
|
|
||||||
'@types/json-schema@7.0.15':
|
'@types/json-schema@7.0.15':
|
||||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||||
|
|
||||||
@ -433,6 +442,9 @@ packages:
|
|||||||
estree-walker@2.0.2:
|
estree-walker@2.0.2:
|
||||||
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
||||||
|
|
||||||
|
eventemitter3@4.0.7:
|
||||||
|
resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
|
||||||
|
|
||||||
events@3.3.0:
|
events@3.3.0:
|
||||||
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
|
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
|
||||||
engines: {node: '>=0.8.x'}
|
engines: {node: '>=0.8.x'}
|
||||||
@ -455,6 +467,15 @@ packages:
|
|||||||
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
follow-redirects@1.15.9:
|
||||||
|
resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
|
||||||
|
engines: {node: '>=4.0'}
|
||||||
|
peerDependencies:
|
||||||
|
debug: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
debug:
|
||||||
|
optional: true
|
||||||
|
|
||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
@ -485,6 +506,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
http-proxy@1.18.1:
|
||||||
|
resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==}
|
||||||
|
engines: {node: '>=8.0.0'}
|
||||||
|
|
||||||
ignore-by-default@1.0.1:
|
ignore-by-default@1.0.1:
|
||||||
resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==}
|
resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==}
|
||||||
|
|
||||||
@ -626,6 +651,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==}
|
resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
|
||||||
|
requires-port@1.0.0:
|
||||||
|
resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
|
||||||
|
|
||||||
resolve@1.22.8:
|
resolve@1.22.8:
|
||||||
resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
|
resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@ -781,8 +809,27 @@ packages:
|
|||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
ws@8.18.0:
|
||||||
|
resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
bufferutil: ^4.0.1
|
||||||
|
utf-8-validate: '>=5.0.2'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
bufferutil:
|
||||||
|
optional: true
|
||||||
|
utf-8-validate:
|
||||||
|
optional: true
|
||||||
|
|
||||||
snapshots:
|
snapshots:
|
||||||
|
|
||||||
|
'@abearxiong/router@0.0.1-alpha.43':
|
||||||
|
dependencies:
|
||||||
|
ws: 8.18.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- bufferutil
|
||||||
|
- utf-8-validate
|
||||||
|
|
||||||
'@abearxiong/use-config@0.0.2': {}
|
'@abearxiong/use-config@0.0.2': {}
|
||||||
|
|
||||||
'@abearxiong/use-file-store@0.0.1(typescript@5.6.3)':
|
'@abearxiong/use-file-store@0.0.1(typescript@5.6.3)':
|
||||||
@ -916,6 +963,10 @@ snapshots:
|
|||||||
|
|
||||||
'@types/estree@1.0.6': {}
|
'@types/estree@1.0.6': {}
|
||||||
|
|
||||||
|
'@types/http-proxy@1.17.15':
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 22.7.5
|
||||||
|
|
||||||
'@types/json-schema@7.0.15': {}
|
'@types/json-schema@7.0.15': {}
|
||||||
|
|
||||||
'@types/node@22.7.5':
|
'@types/node@22.7.5':
|
||||||
@ -1133,6 +1184,8 @@ snapshots:
|
|||||||
|
|
||||||
estree-walker@2.0.2: {}
|
estree-walker@2.0.2: {}
|
||||||
|
|
||||||
|
eventemitter3@4.0.7: {}
|
||||||
|
|
||||||
events@3.3.0: {}
|
events@3.3.0: {}
|
||||||
|
|
||||||
fast-deep-equal@3.1.3: {}
|
fast-deep-equal@3.1.3: {}
|
||||||
@ -1147,6 +1200,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
to-regex-range: 5.0.1
|
to-regex-range: 5.0.1
|
||||||
|
|
||||||
|
follow-redirects@1.15.9: {}
|
||||||
|
|
||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@ -1168,6 +1223,14 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
function-bind: 1.1.2
|
function-bind: 1.1.2
|
||||||
|
|
||||||
|
http-proxy@1.18.1:
|
||||||
|
dependencies:
|
||||||
|
eventemitter3: 4.0.7
|
||||||
|
follow-redirects: 1.15.9
|
||||||
|
requires-port: 1.0.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- debug
|
||||||
|
|
||||||
ignore-by-default@1.0.1: {}
|
ignore-by-default@1.0.1: {}
|
||||||
|
|
||||||
ioredis@5.4.1:
|
ioredis@5.4.1:
|
||||||
@ -1296,6 +1359,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
redis-errors: 1.2.0
|
redis-errors: 1.2.0
|
||||||
|
|
||||||
|
requires-port@1.0.0: {}
|
||||||
|
|
||||||
resolve@1.22.8:
|
resolve@1.22.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-core-module: 2.15.1
|
is-core-module: 2.15.1
|
||||||
@ -1467,3 +1532,5 @@ snapshots:
|
|||||||
which@2.0.2:
|
which@2.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
isexe: 2.0.0
|
isexe: 2.0.0
|
||||||
|
|
||||||
|
ws@8.18.0: {}
|
||||||
|
9
src/app.ts
Normal file
9
src/app.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { App } from '@abearxiong/router';
|
||||||
|
|
||||||
|
export const app = new App({
|
||||||
|
serverOptions: {
|
||||||
|
path: '/api/proxy',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// app.server.on(callback);
|
25
src/index.ts
25
src/index.ts
@ -1,14 +1,21 @@
|
|||||||
import http from 'http';
|
|
||||||
import { handleRequest } from './module/index.ts';
|
import { handleRequest } from './module/index.ts';
|
||||||
import { useConfig } from '@abearxiong/use-config';
|
import { useConfig } from '@abearxiong/use-config';
|
||||||
|
import { app } from './app.ts';
|
||||||
|
import './route/route.ts'
|
||||||
const { port } = useConfig<{ port: number }>();
|
const { port } = useConfig<{ port: number }>();
|
||||||
const server = http.createServer((req, res) => {
|
|
||||||
// res.writeHead(200, { 'Content-Type': 'text/plain' });
|
app
|
||||||
// const pathname = new URL(req.url, `http://${dns.hostName}`).pathname;
|
.route({
|
||||||
handleRequest(req, res);
|
path: 'hello',
|
||||||
// res.write(`Request from ${dns.hostName} with IP: ${dns.ip}\n`);
|
key: '0',
|
||||||
// res.end('Hello World\n');
|
})
|
||||||
});
|
.define(async (ctx) => {
|
||||||
server.listen(port, () => {
|
ctx.body = 'hello world';
|
||||||
|
})
|
||||||
|
.addTo(app);
|
||||||
|
|
||||||
|
app.listen(port, () => {
|
||||||
console.log(`Server running at http://localhost:${port}/`);
|
console.log(`Server running at http://localhost:${port}/`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.server.on(handleRequest);
|
||||||
|
@ -8,9 +8,11 @@ import { useConfig } from '@abearxiong/use-config';
|
|||||||
import { redis } from './redis/redis.ts';
|
import { redis } from './redis/redis.ts';
|
||||||
import { getContentType } from './get-content-type.ts';
|
import { getContentType } from './get-content-type.ts';
|
||||||
import { sleep } from '@/utils/sleep.ts';
|
import { sleep } from '@/utils/sleep.ts';
|
||||||
|
import { handleProxyRequest } from './proxy.ts';
|
||||||
const { api, domain, allowedOrigins } = useConfig<{
|
const { api, domain, allowedOrigins } = useConfig<{
|
||||||
api: {
|
api: {
|
||||||
host: string;
|
host: string;
|
||||||
|
port?: number;
|
||||||
};
|
};
|
||||||
domain: string;
|
domain: string;
|
||||||
allowedOrigins: string[];
|
allowedOrigins: string[];
|
||||||
@ -19,6 +21,60 @@ const { api, domain, allowedOrigins } = useConfig<{
|
|||||||
const fileStore = useFileStore('upload');
|
const fileStore = useFileStore('upload');
|
||||||
const noProxyUrl = ['/', '/favicon.ico'];
|
const noProxyUrl = ['/', '/favicon.ico'];
|
||||||
export const handleRequest = async (req: http.IncomingMessage, res: http.ServerResponse) => {
|
export const handleRequest = async (req: http.IncomingMessage, res: http.ServerResponse) => {
|
||||||
|
if (req.url === '/favicon.ico') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (req.url.startsWith('/api/router')) {
|
||||||
|
// 代理到 http://codeflow.xiongxiao.me/api
|
||||||
|
const _u = new URL(req.url, `http://${api.host}`);
|
||||||
|
// 设置代理请求的目标 URL 和请求头
|
||||||
|
let header: any = {};
|
||||||
|
if (req.headers?.['Authroization']) {
|
||||||
|
header.Authorization = req.headers?.['Authroization'];
|
||||||
|
}
|
||||||
|
if (req.headers?.['Content-Type']) {
|
||||||
|
header['Content-Type'] = req.headers?.['Content-Type'];
|
||||||
|
}
|
||||||
|
const options = {
|
||||||
|
host: _u.hostname,
|
||||||
|
path: req.url,
|
||||||
|
method: req.method,
|
||||||
|
headers: {
|
||||||
|
...header,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if (_u.port) {
|
||||||
|
// @ts-ignore
|
||||||
|
options.port = _u.port;
|
||||||
|
}
|
||||||
|
// 创建代理请求
|
||||||
|
const proxyReq = http.request(options, (proxyRes) => {
|
||||||
|
// 将代理服务器的响应头和状态码返回给客户端
|
||||||
|
res.writeHead(proxyRes.statusCode, proxyRes.headers);
|
||||||
|
// 将代理响应流写入客户端响应
|
||||||
|
proxyRes.pipe(res, { end: true });
|
||||||
|
});
|
||||||
|
// 处理代理请求的错误事件
|
||||||
|
proxyReq.on('error', (err) => {
|
||||||
|
console.error(`Proxy request error: ${err.message}`);
|
||||||
|
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
||||||
|
res.write(`Proxy request error: ${err.message}`);
|
||||||
|
});
|
||||||
|
// 处理 POST 请求的请求体(传递数据到目标服务器)
|
||||||
|
req.pipe(proxyReq, { end: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (req.url.startsWith('/api/proxy')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (req.url.startsWith('/api')) {
|
||||||
|
res.end('not catch api');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (req.url.startsWith('/test')) {
|
||||||
|
handleProxyRequest(req, res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const dns = getDNS(req);
|
const dns = getDNS(req);
|
||||||
// 配置可以跨域
|
// 配置可以跨域
|
||||||
// 配置可以访问的域名 localhost, xiongxiao.me
|
// 配置可以访问的域名 localhost, xiongxiao.me
|
||||||
@ -87,42 +143,7 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
|
|||||||
user = _user;
|
user = _user;
|
||||||
app = _app;
|
app = _app;
|
||||||
}
|
}
|
||||||
const [_, _api] = req.url.split('/');
|
|
||||||
if (_api === 'api') {
|
|
||||||
// 代理到 http://codeflow.xiongxiao.me/api
|
|
||||||
// 设置代理请求的目标 URL 和请求头
|
|
||||||
let header: any = {};
|
|
||||||
if (req.headers?.['Authroization']) {
|
|
||||||
header.Authorization = req.headers?.['Authroization'];
|
|
||||||
}
|
|
||||||
if (req.headers?.['Content-Type']) {
|
|
||||||
header['Content-Type'] = req.headers?.['Content-Type'];
|
|
||||||
}
|
|
||||||
const options = {
|
|
||||||
host: api.host,
|
|
||||||
path: req.url,
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
...header,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
// 创建代理请求
|
|
||||||
const proxyReq = http.request(options, (proxyRes) => {
|
|
||||||
// 将代理服务器的响应头和状态码返回给客户端
|
|
||||||
res.writeHead(proxyRes.statusCode, proxyRes.headers);
|
|
||||||
// 将代理响应流写入客户端响应
|
|
||||||
proxyRes.pipe(res, { end: true });
|
|
||||||
});
|
|
||||||
// 处理代理请求的错误事件
|
|
||||||
proxyReq.on('error', (err) => {
|
|
||||||
console.error(`Proxy request error: ${err.message}`);
|
|
||||||
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
|
||||||
res.write(`Proxy request error: ${err.message}`);
|
|
||||||
});
|
|
||||||
// 处理 POST 请求的请求体(传递数据到目标服务器)
|
|
||||||
req.pipe(proxyReq, { end: true });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const userApp = new UserApp({ user, app });
|
const userApp = new UserApp({ user, app });
|
||||||
let isExist = await userApp.getExist();
|
let isExist = await userApp.getExist();
|
||||||
if (!isExist) {
|
if (!isExist) {
|
||||||
|
64
src/module/proxy.ts
Normal file
64
src/module/proxy.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import http from 'http';
|
||||||
|
import httpProxy from 'http-proxy';
|
||||||
|
import { useConfig } from '@abearxiong/use-config';
|
||||||
|
|
||||||
|
const { resources, api } = useConfig<{
|
||||||
|
resources: string;
|
||||||
|
api: { host: string };
|
||||||
|
}>();
|
||||||
|
const proxy = httpProxy.createProxyServer({});
|
||||||
|
const fetchTest = async (id: string) => {
|
||||||
|
const fetchUrl = 'http://' + api.host + '/api/router';
|
||||||
|
const fetchRes = await fetch(fetchUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
path: 'user-app',
|
||||||
|
key: 'test',
|
||||||
|
id: id,
|
||||||
|
}),
|
||||||
|
}).then((res) => res.json());
|
||||||
|
return fetchRes;
|
||||||
|
};
|
||||||
|
// 60939f5e-f51b-4563-8c96-7a98ac5ac259
|
||||||
|
export const handleProxyRequest = async (req: http.IncomingMessage, res: http.ServerResponse) => {
|
||||||
|
const url = req.url;
|
||||||
|
const urls = url.split('/');
|
||||||
|
const [_, test, id] = urls;
|
||||||
|
const error = (msg: string) => {
|
||||||
|
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
||||||
|
res.write(msg);
|
||||||
|
res.end();
|
||||||
|
};
|
||||||
|
if (test !== 'test') {
|
||||||
|
error('Not Found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!id) {
|
||||||
|
error('Need Test ID');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 判断id是uuid
|
||||||
|
if (!isUUID(id)) {
|
||||||
|
error('Need Test ID is UUID');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const result = await fetchTest(id);
|
||||||
|
console.log('data', result);
|
||||||
|
if (result.code !== 200) {
|
||||||
|
error('fetch error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const files = result.data?.data?.files;
|
||||||
|
const appFileUrl = (url + '').replace(`/${test}/${id}/`, '');
|
||||||
|
const pathFile = files.find((file: any) => file.name === appFileUrl);
|
||||||
|
const target = `https://${resources}/${pathFile.path}`;
|
||||||
|
console.log('target', target);
|
||||||
|
proxy.web(req, res, { target: target, secure: false });
|
||||||
|
};
|
||||||
|
function isUUID(id: string): boolean {
|
||||||
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
||||||
|
return uuidRegex.test(id);
|
||||||
|
}
|
40
src/module/query/get-router.ts
Normal file
40
src/module/query/get-router.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { useConfig } from '@abearxiong/use-config';
|
||||||
|
|
||||||
|
const { resources, api } = useConfig<{
|
||||||
|
resources: string;
|
||||||
|
api: { host: string };
|
||||||
|
}>();
|
||||||
|
|
||||||
|
export const fetchTest = async (id: string) => {
|
||||||
|
const fetchUrl = 'http://' + api.host + '/api/router';
|
||||||
|
const fetchRes = await fetch(fetchUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
path: 'user-app',
|
||||||
|
key: 'test',
|
||||||
|
id: id,
|
||||||
|
}),
|
||||||
|
}).then((res) => res.json());
|
||||||
|
return fetchRes;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const fetchDomain = async (domain: string) => {
|
||||||
|
const fetchUrl = 'http://' + api.host + '/api/router';
|
||||||
|
const fetchRes = await fetch(fetchUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
path: 'app',
|
||||||
|
key: 'getDomainApp',
|
||||||
|
data: {
|
||||||
|
domain,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}).then((res) => res.json());
|
||||||
|
return fetchRes;
|
||||||
|
};
|
1
src/route/app/index.ts
Normal file
1
src/route/app/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
import './list.ts'
|
72
src/route/app/list.ts
Normal file
72
src/route/app/list.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { UserApp } from '@/module/get-user-app.ts';
|
||||||
|
import { app } from '../../app.ts';
|
||||||
|
import { redis } from '@/module/redis/redis.ts';
|
||||||
|
import { CustomError } from '@abearxiong/router';
|
||||||
|
import fs from 'fs';
|
||||||
|
import { useFileStore } from '@abearxiong/use-file-store';
|
||||||
|
const fileStore = useFileStore('upload');
|
||||||
|
|
||||||
|
app
|
||||||
|
.route({
|
||||||
|
path: 'app',
|
||||||
|
key: 'list',
|
||||||
|
})
|
||||||
|
.define(async (ctx) => {
|
||||||
|
const keys = await redis.keys('user:app:*');
|
||||||
|
// const keys = await redis.keys('user:app:exist:*');
|
||||||
|
// const data = await redis.mget(...keys);
|
||||||
|
ctx.body = {
|
||||||
|
// data: data,
|
||||||
|
keys,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.addTo(app);
|
||||||
|
|
||||||
|
app
|
||||||
|
.route({
|
||||||
|
path: 'app',
|
||||||
|
key: 'delete',
|
||||||
|
})
|
||||||
|
.define(async (ctx) => {
|
||||||
|
const { user, app } = ctx.query;
|
||||||
|
try {
|
||||||
|
const userApp = new UserApp({ user, app });
|
||||||
|
await userApp.clearCacheData();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
throw new CustomError('删除失败');
|
||||||
|
}
|
||||||
|
ctx.body = 'successfully';
|
||||||
|
})
|
||||||
|
.addTo(app);
|
||||||
|
|
||||||
|
app
|
||||||
|
.route({
|
||||||
|
path: 'app',
|
||||||
|
key: 'deleteAll',
|
||||||
|
})
|
||||||
|
.define(async (ctx) => {
|
||||||
|
const keys = await redis.keys('user:app:*');
|
||||||
|
for (const key of keys) {
|
||||||
|
await redis.set(key, '', 'EX', 1);
|
||||||
|
}
|
||||||
|
ctx.body = {
|
||||||
|
keys,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.addTo(app);
|
||||||
|
|
||||||
|
app
|
||||||
|
.route({
|
||||||
|
path: 'app',
|
||||||
|
key: 'deleteAllForce',
|
||||||
|
})
|
||||||
|
.define(async (ctx) => {
|
||||||
|
const keys = await redis.keys('user:app:*');
|
||||||
|
await redis.del(...keys);
|
||||||
|
fs.rmSync(fileStore, { recursive: true });
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
keys,
|
||||||
|
};
|
||||||
|
});
|
1
src/route/route.ts
Normal file
1
src/route/route.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
import './app/index.ts'
|
Loading…
x
Reference in New Issue
Block a user