我如何通过动态的反向代理和发布请求来解决我的问题?

问题描述 投票:0回答:1
因此,我正在尝试设置一个系统,该系统允许流量根据数据库中存储的项目ID重定向到Docker容器。我使用nginx作为代理反向代理的反向代理,这可能不是超级效率,但似乎对获取请求有效,但发布请求最终会定时出现。我怀疑它是码头容器,它正在替代请求导致错误,因为该登机码的日志似乎没有输出任何内容。 这是我的动态反向代理的代码:


import Fastify, { FastifyRequest } from 'fastify'; import { db } from './db'; import { routingTable } from './db/schema'; import { eq } from 'drizzle-orm'; import dotenv from 'dotenv'; import Docker from 'dockerode'; import httpProxy from 'http-proxy'; import crypto from 'crypto'; import fastifyFormBody from '@fastify/formbody'; import fastifyMultipart from '@fastify/multipart'; dotenv.config(); const fastify = Fastify({ logger: true, // Increase body size limits for proxying larger POST requests bodyLimit: 30 * 1024 * 1024 // 30MB }); // Register fastify body parser plugins to handle different content types fastify.register(fastifyFormBody); fastify.register(fastifyMultipart, { limits: { fileSize: 25 * 1024 * 1024 // 25MB limit for file uploads } }); // Create a proxy server instance const proxy = httpProxy.createProxyServer({ changeOrigin: true, xfwd: true, // Add X-Forwarded headers proxyTimeout: 120000, // Increase timeout to 2 minutes buffer: undefined, // Let the proxy handle buffering based on the request }); // Add special handling for the proxy proxy.on('proxyReq', (proxyReq, req, res, options) => { // Ensure content-length is preserved for requests with bodies if (req.headers['content-length']) { proxyReq.setHeader('Content-Length', req.headers['content-length']); } // Ensure content-type is preserved if (req.headers['content-type']) { proxyReq.setHeader('Content-Type', req.headers['content-type']); } }); // Add response handling to manage incoming responses proxy.on('proxyRes', (proxyRes, req, res) => { fastify.log.info(`Received proxy response from target with status: ${proxyRes.statusCode}`); }); // Handle proxy errors // @ts-ignore - Ignore TypeScript errors for now as the http-proxy types are hard to match exactly proxy.on('error', function(err: any, req: any, res: any) { if (res.writeHead) { fastify.log.error(`Proxy error: ${err.message}`); res.writeHead(500, { 'Content-Type': 'text/plain' }); res.end('Proxy error: ' + err.message); } }); const docker = new Docker({ socketPath: '/var/run/docker.sock' }); // Define a route for handling all requests fastify.all('*', async (request, reply) => { const host = request.headers.host; if (!host) { return reply.status(400).send({ error: "Host header is required" }); } const hostParts = host.split('.'); let subdomain = hostParts.at(0) ?? null; if (!subdomain) { return reply.status(400).send({ error: "Invalid host format" }); } const useActionRunner = subdomain.includes("action"); if (useActionRunner) { subdomain = subdomain.replace('-action', ''); } // If the subdomain is "server", allow access to server endpoints directly if (subdomain.toLowerCase() === 'server') { // Skip proxying and let the request continue to other routes return; } // Query PostgreSQL for the port const result = await db .select() .from(routingTable) .where(eq(routingTable.projectId, subdomain)); if (result.length === 0) { return reply.status(404).send({ error: "Project not found" }); } // Use http-proxy instead of reply.from() const targetUrl = useActionRunner ? `http://localhost:${result[0].action_port}` : `http://localhost:${result[0].host_port}`; // Set up a custom completion handler const proxyHandler = (callback: () => void) => { // Mark the response as handled reply.hijack(); const options: httpProxy.ServerOptions = { target: targetUrl, ignorePath: false, prependPath: false, selfHandleResponse: false, timeout: 120000 // Match the main proxy timeout }; // Handle different types of requests if (request.method === 'POST' || request.method === 'PUT' || request.method === 'PATCH') { // For requests with bodies, ensure the content-type and body are preserved fastify.log.info(`Proxying ${request.method} request to ${targetUrl}${request.url} with Content-Type: ${request.headers['content-type']}, Content-Length: ${request.headers['content-length']}`); // Add special handling for POST requests to ensure the body gets forwarded properly const startTime = Date.now(); // Set a longer timeout for the request to complete const reqTimeout = setTimeout(() => { fastify.log.error(`Request to ${targetUrl}${request.url} timed out after ${Date.now() - startTime}ms`); callback(); }, 115000); // Slightly less than the main proxy timeout // Listen for the response to complete request.raw.on('close', () => { clearTimeout(reqTimeout); const duration = Date.now() - startTime; fastify.log.info(`Request to ${targetUrl}${request.url} completed in ${duration}ms`); callback(); }); } else { fastify.log.info(`Proxying ${request.method} request to ${targetUrl}${request.url}`); } // Ensure the raw request is directly passed to the proxy // This preserves the original request body for POST requests proxy.web(request.raw, reply.raw, options, (err) => { if (err) { fastify.log.error(`Proxy error in web(): ${err.message}`); } callback(); }); }; // Handle completion/errors return new Promise<void>((resolve, reject) => { proxyHandler(() => { resolve(); }); }); }); // Run the server! async function start() { try { await fastify.listen({ port: 8080, host: '0.0.0.0' // Listen on all network interfaces }); } catch (err) { fastify.log.error(err); } } start();

	
typescript docker reverse-proxy fastify
1个回答
0
投票
request.body

属性就在那里,因此

request.raw
流已经读取(因此不可能再次将其管道)。
您需要添加一个虚拟内容类型解析器:

fastify.addContentTypeParser('*', function (request, payload, done) { done() })

docs参考
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.