fix: 配置修改,添加socket代理
This commit is contained in:
parent
d548d3ab04
commit
bb86a7c507
@ -1,8 +1,18 @@
|
||||
{
|
||||
api: {
|
||||
host: 'localhost:4002', // 后台代理
|
||||
target: 'http://localhost:4002', // 后台代理
|
||||
path: '/api/router',
|
||||
},
|
||||
apiList: [
|
||||
{
|
||||
path: '/api/router',
|
||||
target: 'http://localhost:4002',
|
||||
},
|
||||
{
|
||||
path: '/api/v1',
|
||||
target: 'http://localhost:3005',
|
||||
},
|
||||
],
|
||||
proxy: {
|
||||
port: 3005,
|
||||
domain: 'kevisual.xiongxiao.me',
|
||||
|
21
package.json
21
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "page-proxy",
|
||||
"version": "0.0.2-beta.1",
|
||||
"version": "0.0.2-beta.3",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
@ -35,22 +35,25 @@
|
||||
"@rollup/plugin-node-resolve": "^16.0.0",
|
||||
"@rollup/plugin-typescript": "^12.1.2",
|
||||
"@types/http-proxy": "^1.17.16",
|
||||
"@types/node": "^22.13.5",
|
||||
"@types/node": "^22.13.9",
|
||||
"@types/send": "^0.17.4",
|
||||
"concurrently": "^9.1.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"nodemon": "^3.1.9",
|
||||
"rollup": "^4.34.8",
|
||||
"rollup": "^4.34.9",
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.7.3"
|
||||
"typescript": "^5.8.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@kevisual/code-center-module": "0.0.11-alpha.1",
|
||||
"@kevisual/router": "0.0.7",
|
||||
"@kevisual/use-config": "^1.0.8",
|
||||
"@kevisual/code-center-module": "0.0.11-alpha.3",
|
||||
"@kevisual/router": "0.0.9",
|
||||
"@kevisual/use-config": "^1.0.9",
|
||||
"archiver": "^7.0.1",
|
||||
"ioredis": "^5.5.0",
|
||||
"ioredis": "^5.6.0",
|
||||
"minio": "^8.0.4",
|
||||
"nanoid": "^5.1.2",
|
||||
"sequelize": "^6.37.5"
|
||||
"send": "^1.1.0",
|
||||
"sequelize": "^6.37.6"
|
||||
},
|
||||
"resolutions": {
|
||||
"picomatch": "^4.0.2"
|
||||
|
821
pnpm-lock.yaml
generated
821
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
45
src/index.ts
45
src/index.ts
@ -2,6 +2,7 @@ import { handleRequest } from './module/index.ts';
|
||||
import { config } from './module/config.ts';
|
||||
import { app } from './app.ts';
|
||||
import './route/route.ts';
|
||||
import net from 'net';
|
||||
const port = config?.proxy?.port || 3005;
|
||||
|
||||
app
|
||||
@ -19,3 +20,47 @@ app.listen(port, () => {
|
||||
});
|
||||
|
||||
app.server.on(handleRequest);
|
||||
|
||||
const main = () => {
|
||||
console.log('Upgrade initialization started');
|
||||
|
||||
app.server.server.on('upgrade', (req, socket, head) => {
|
||||
const proxyApiList = config?.apiList || [];
|
||||
const proxyApi = proxyApiList.find((item) => req.url.startsWith(item.path));
|
||||
|
||||
if (proxyApi) {
|
||||
const _u = new URL(req.url, `${proxyApi.target}`);
|
||||
const options = {
|
||||
hostname: _u.hostname,
|
||||
port: Number(_u.port) || 80,
|
||||
path: _u.pathname,
|
||||
headers: req.headers,
|
||||
};
|
||||
|
||||
const proxySocket = net.connect(options.port, options.hostname, () => {
|
||||
proxySocket.write(
|
||||
`GET ${options.path} HTTP/1.1\r\n` +
|
||||
`Host: ${options.hostname}\r\n` +
|
||||
`Connection: Upgrade\r\n` +
|
||||
`Upgrade: websocket\r\n` +
|
||||
`Sec-WebSocket-Key: ${req.headers['sec-websocket-key']}\r\n` +
|
||||
`Sec-WebSocket-Version: ${req.headers['sec-websocket-version']}\r\n` +
|
||||
`\r\n`
|
||||
);
|
||||
proxySocket.pipe(socket);
|
||||
socket.pipe(proxySocket);
|
||||
});
|
||||
|
||||
proxySocket.on('error', (err) => {
|
||||
console.error(`WebSocket proxy error: ${err.message}`);
|
||||
socket.end();
|
||||
});
|
||||
} else {
|
||||
socket.end();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
setTimeout(() => {
|
||||
main();
|
||||
}, 1200);
|
||||
|
@ -11,6 +11,17 @@ type ConfigType = {
|
||||
path?: string;
|
||||
port?: number;
|
||||
};
|
||||
apiList: {
|
||||
path: string;
|
||||
/**
|
||||
* url或者相对路径
|
||||
*/
|
||||
target: string;
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
type?: 'static' | 'dynamic' | 'minio';
|
||||
}[];
|
||||
proxy: {
|
||||
port?: number;
|
||||
/**
|
||||
|
@ -6,6 +6,8 @@ import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { getContentType } from './get-content-type.ts';
|
||||
import { createRefreshHtml } from './html/create-refresh-html.ts';
|
||||
import { fileProxy } from './proxy/file-proxy.ts';
|
||||
import net from 'net';
|
||||
|
||||
const api = config?.api || { host: 'kevisual.xiongxiao.me', path: '/api/router' };
|
||||
const domain = config?.proxy?.domain || 'kevisual.xiongxiao.me';
|
||||
@ -20,11 +22,18 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
|
||||
return;
|
||||
}
|
||||
if (req.url.startsWith('/api/proxy')) {
|
||||
// 已经代理过了
|
||||
return;
|
||||
}
|
||||
if (req.url.startsWith('/api')) {
|
||||
// 代理到 http://codeflow.xiongxiao.me/api
|
||||
const _u = new URL(req.url, `http://${api.host}`);
|
||||
console.log('req', req.url, 'len', config?.apiList?.length);
|
||||
const proxyApiList = config?.apiList || [];
|
||||
const proxyApi = proxyApiList.find((item) => req.url.startsWith(item.path));
|
||||
if (proxyApi && proxyApi?.type === 'static') {
|
||||
return fileProxy(req, res, proxyApi);
|
||||
}
|
||||
if (proxyApi) {
|
||||
const _u = new URL(req.url, `${proxyApi.target}`);
|
||||
console.log('proxyApi', req.url, _u.href);
|
||||
// 设置代理请求的目标 URL 和请求头
|
||||
let header: any = {};
|
||||
if (req.headers?.['Authorization']) {
|
||||
@ -32,9 +41,11 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
|
||||
} else if (req.headers?.['authorization']) {
|
||||
header.authorization = req.headers['authorization'];
|
||||
}
|
||||
if (req.headers?.['Content-Type']) {
|
||||
header['Content-Type'] = req.headers?.['Content-Type'];
|
||||
}
|
||||
// 提取req的headers中的非HOST的header
|
||||
const headers = Object.keys(req.headers).filter((item) => item && item.toLowerCase() !== 'host');
|
||||
headers.forEach((item) => {
|
||||
header[item] = req.headers[item];
|
||||
});
|
||||
const options = {
|
||||
host: _u.hostname,
|
||||
path: req.url,
|
||||
@ -64,7 +75,7 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
|
||||
req.pipe(proxyReq, { end: true });
|
||||
return;
|
||||
}
|
||||
if (req.url.startsWith('/api')) {
|
||||
if (req.url.startsWith('/api') || req.url.startsWith('/v1')) {
|
||||
res.end('not catch api');
|
||||
return;
|
||||
}
|
||||
@ -244,3 +255,4 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
|
||||
console.error('getFile error', error);
|
||||
}
|
||||
};
|
||||
|
||||
|
24
src/module/minio.ts
Normal file
24
src/module/minio.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { Client, ClientOptions } from 'minio';
|
||||
import { useConfig } from '@kevisual/use-config';
|
||||
|
||||
type MinioConfig = {
|
||||
minio: ClientOptions & { bucketName: string };
|
||||
};
|
||||
const config = useConfig<MinioConfig>();
|
||||
|
||||
const { bucketName, ...minioRest } = config.minio;
|
||||
export const minioClient = new Client(minioRest);
|
||||
export { bucketName };
|
||||
if (!minioClient) {
|
||||
throw new Error('Minio client not initialized');
|
||||
}
|
||||
// 验证权限
|
||||
// (async () => {
|
||||
// const bucketExists = await minioClient.bucketExists(bucketName);
|
||||
// if (!bucketExists) {
|
||||
// await minioClient.makeBucket(bucketName);
|
||||
// }
|
||||
// const res = await minioClient.putObject(bucketName, 'private/test/a.b', 'test');
|
||||
// console.log('minio putObject', res);
|
||||
|
||||
// })();
|
26
src/module/proxy/file-proxy.ts
Normal file
26
src/module/proxy/file-proxy.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import http from 'http';
|
||||
import send from 'send';
|
||||
import fs from 'fs';
|
||||
import { fileIsExist } from '@kevisual/use-config';
|
||||
import path from 'path';
|
||||
export type ProxyInfo = {
|
||||
path?: string;
|
||||
target: string;
|
||||
type?: 'static' | 'dynamic' | 'minio';
|
||||
};
|
||||
export const fileProxy = (req: http.IncomingMessage, res: http.ServerResponse, proxyApi: ProxyInfo) => {
|
||||
// url开头的文件
|
||||
const url = new URL(req.url, 'http://localhost');
|
||||
const pathname = url.pathname;
|
||||
// 检测文件是否存在,如果文件不存在,则返回404
|
||||
const filePath = path.join(process.cwd(), proxyApi.target, pathname);
|
||||
if (!fileIsExist(filePath)) {
|
||||
res.statusCode = 404;
|
||||
res.end('Not Found File');
|
||||
return;
|
||||
}
|
||||
const file = send(req, pathname, {
|
||||
root: proxyApi.target,
|
||||
});
|
||||
file.pipe(res);
|
||||
};
|
24
src/module/proxy/minio-proxy.ts
Normal file
24
src/module/proxy/minio-proxy.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import http from 'http';
|
||||
import { minioClient } from '../minio.ts';
|
||||
export type ProxyInfo = {
|
||||
path?: string;
|
||||
target: string;
|
||||
type?: 'static' | 'dynamic' | 'minio';
|
||||
};
|
||||
export const minioProxy = async (req: http.IncomingMessage, res: http.ServerResponse, proxyApi: ProxyInfo) => {
|
||||
try {
|
||||
const requestUrl = new URL(req.url, 'http://localhost');
|
||||
const objectPath = requestUrl.pathname;
|
||||
const bucketName = proxyApi.target;
|
||||
let objectName = objectPath.slice(1);
|
||||
if (objectName.startsWith(bucketName)) {
|
||||
objectName = objectName.slice(bucketName.length);
|
||||
}
|
||||
const objectStream = await minioClient.getObject(bucketName, objectName);
|
||||
objectStream.pipe(res);
|
||||
} catch (error) {
|
||||
console.error('Error fetching object from MinIO:', error);
|
||||
res.statusCode = 500;
|
||||
res.end('Internal Server Error');
|
||||
}
|
||||
};
|
18
src/scripts/test-net-socket.ts
Normal file
18
src/scripts/test-net-socket.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import net from 'net';
|
||||
|
||||
const main = () => {
|
||||
const options = {
|
||||
port: 3003,
|
||||
hostname: '192.168.31.220',
|
||||
path: '/api/v1',
|
||||
};
|
||||
const proxySocket = net.connect(options.port, options.hostname, () => {
|
||||
proxySocket.write(`GET ${options.path} HTTP/1.1\r\n` + `Host: ${options.hostname}\r\n` + `Connection: Upgrade\r\n` + `Upgrade: websocket\r\n` + `\r\n`);
|
||||
});
|
||||
|
||||
proxySocket.on('data', (data) => {
|
||||
console.log('data', data.toString());
|
||||
});
|
||||
};
|
||||
|
||||
main();
|
Loading…
x
Reference in New Issue
Block a user