mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-29 14:06:36 +08:00
162 lines
4.0 KiB
JavaScript
162 lines
4.0 KiB
JavaScript
import http from 'node:http';
|
|
import https from 'node:https';
|
|
|
|
import next from 'next';
|
|
|
|
const port = Number.parseInt(process.env.PORT ?? '3001', 10);
|
|
const hostname = process.env.HOSTNAME || '127.0.0.1';
|
|
const backendBaseUrl = new URL(
|
|
(process.env.NEXT_DEV_BACKEND_URL || 'http://127.0.0.1:3000').replace(/\/+$/, ''),
|
|
);
|
|
|
|
const app = next({
|
|
dev: true,
|
|
hostname,
|
|
port,
|
|
});
|
|
|
|
let handle;
|
|
let handleUpgrade;
|
|
|
|
function isApiRequest(url = '') {
|
|
return url.startsWith('/api/');
|
|
}
|
|
|
|
function createProxyRequestOptions(req, targetUrl) {
|
|
const headers = {
|
|
...req.headers,
|
|
host: targetUrl.host,
|
|
};
|
|
|
|
if (headers.origin) {
|
|
headers.origin = targetUrl.origin;
|
|
}
|
|
|
|
return {
|
|
protocol: targetUrl.protocol,
|
|
hostname: targetUrl.hostname,
|
|
port: targetUrl.port || (targetUrl.protocol === 'https:' ? 443 : 80),
|
|
method: req.method,
|
|
path: `${targetUrl.pathname}${targetUrl.search}`,
|
|
headers,
|
|
};
|
|
}
|
|
|
|
function writeProxyError(res, error) {
|
|
res.statusCode = 502;
|
|
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
res.end(
|
|
JSON.stringify({
|
|
success: false,
|
|
message: `开发代理连接后端失败: ${error.message}`,
|
|
}),
|
|
);
|
|
}
|
|
|
|
function proxyHttpRequest(req, res) {
|
|
const targetUrl = new URL(req.url || '/', backendBaseUrl);
|
|
const requestImpl = targetUrl.protocol === 'https:' ? https.request : http.request;
|
|
const proxyReq = requestImpl(createProxyRequestOptions(req, targetUrl), (proxyRes) => {
|
|
res.writeHead(proxyRes.statusCode || 502, proxyRes.statusMessage, proxyRes.headers);
|
|
proxyRes.pipe(res);
|
|
});
|
|
|
|
proxyReq.on('error', (error) => {
|
|
if (!res.headersSent) {
|
|
writeProxyError(res, error);
|
|
return;
|
|
}
|
|
res.destroy(error);
|
|
});
|
|
|
|
req.pipe(proxyReq);
|
|
}
|
|
|
|
function formatUpgradeResponseHeaders(statusCode, statusMessage, headers) {
|
|
const lines = [`HTTP/1.1 ${statusCode} ${statusMessage}`];
|
|
for (const [key, value] of Object.entries(headers)) {
|
|
if (value === undefined) {
|
|
continue;
|
|
}
|
|
if (Array.isArray(value)) {
|
|
for (const item of value) {
|
|
lines.push(`${key}: ${item}`);
|
|
}
|
|
continue;
|
|
}
|
|
lines.push(`${key}: ${value}`);
|
|
}
|
|
lines.push('', '');
|
|
return lines.join('\r\n');
|
|
}
|
|
|
|
function proxyWebSocketUpgrade(req, socket, head) {
|
|
const targetUrl = new URL(req.url || '/', backendBaseUrl);
|
|
const requestImpl = targetUrl.protocol === 'https:' ? https.request : http.request;
|
|
const proxyReq = requestImpl(createProxyRequestOptions(req, targetUrl));
|
|
|
|
proxyReq.on('upgrade', (proxyRes, proxySocket, proxyHead) => {
|
|
socket.write(
|
|
formatUpgradeResponseHeaders(
|
|
proxyRes.statusCode || 101,
|
|
proxyRes.statusMessage || 'Switching Protocols',
|
|
proxyRes.headers,
|
|
),
|
|
);
|
|
|
|
if (head.length > 0) {
|
|
proxySocket.write(head);
|
|
}
|
|
if (proxyHead.length > 0) {
|
|
socket.write(proxyHead);
|
|
}
|
|
|
|
proxySocket.pipe(socket).pipe(proxySocket);
|
|
|
|
proxySocket.on('error', () => socket.destroy());
|
|
socket.on('error', () => proxySocket.destroy());
|
|
});
|
|
|
|
proxyReq.on('response', (proxyRes) => {
|
|
socket.write(
|
|
formatUpgradeResponseHeaders(
|
|
proxyRes.statusCode || 502,
|
|
proxyRes.statusMessage || 'Bad Gateway',
|
|
proxyRes.headers,
|
|
),
|
|
);
|
|
proxyRes.pipe(socket);
|
|
});
|
|
|
|
proxyReq.on('error', () => {
|
|
socket.destroy();
|
|
});
|
|
|
|
proxyReq.end();
|
|
}
|
|
|
|
await app.prepare();
|
|
handle = app.getRequestHandler();
|
|
handleUpgrade = app.getUpgradeHandler();
|
|
|
|
const server = http.createServer((req, res) => {
|
|
if (isApiRequest(req.url)) {
|
|
proxyHttpRequest(req, res);
|
|
return;
|
|
}
|
|
handle(req, res);
|
|
});
|
|
|
|
server.on('upgrade', (req, socket, head) => {
|
|
if (isApiRequest(req.url)) {
|
|
proxyWebSocketUpgrade(req, socket, head);
|
|
return;
|
|
}
|
|
handleUpgrade(req, socket, head);
|
|
});
|
|
|
|
server.listen(port, hostname, () => {
|
|
console.log(`OpenFlare web dev server listening on http://${hostname}:${port}`);
|
|
console.log(`Proxying /api/* and websocket upgrades to ${backendBaseUrl.href}`);
|
|
});
|