This commit is contained in:
2024-10-15 18:05:00 +08:00
parent c92f817d66
commit 6b5eec89ed
11 changed files with 331 additions and 47 deletions

View File

@@ -8,9 +8,11 @@ import { useConfig } from '@abearxiong/use-config';
import { redis } from './redis/redis.ts';
import { getContentType } from './get-content-type.ts';
import { sleep } from '@/utils/sleep.ts';
import { handleProxyRequest } from './proxy.ts';
const { api, domain, allowedOrigins } = useConfig<{
api: {
host: string;
port?: number;
};
domain: string;
allowedOrigins: string[];
@@ -19,6 +21,60 @@ const { api, domain, allowedOrigins } = useConfig<{
const fileStore = useFileStore('upload');
const noProxyUrl = ['/', '/favicon.ico'];
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);
// 配置可以跨域
// 配置可以访问的域名 localhost, xiongxiao.me
@@ -87,42 +143,7 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
user = _user;
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 });
let isExist = await userApp.getExist();
if (!isExist) {

64
src/module/proxy.ts Normal file
View 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);
}

View 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;
};