如何用Node.js Express的Rendertron中间件重定向至原Angular应用
解决Rendertron中间件转发非Bot请求到原应用的问题
核心问题分析
你的代码存在两个关键问题:
- 固定请求地址丢失用户实际请求路径:当前
fetch直接请求固定地址,没有携带用户访问的具体路由(比如/about),导致原应用无法返回对应页面。 - 仅处理GET请求且未完整传递请求/响应信息:只实现了
app.get('*'),忽略了POST/PUT等方法;同时没有传递原请求的headers、body,也未将原应用的响应头(如Content-Type、Cache-Control等)返回给客户端,导致页面样式、资源加载失败。
修复方案
1. 转发所有HTTP方法的请求
使用app.all('*')替代app.get('*'),覆盖所有请求方法(GET/POST/PUT/DELETE等)。
2. 动态拼接目标请求地址
将用户请求的path拼接至原应用地址后,确保请求对应路由。
3. 完整传递请求信息
转发原请求的headers、method、body(针对非GET请求)到原应用。
4. 完整返回响应信息
将原应用的响应头、状态码、响应体完整返回给客户端,确保页面正常渲染。
完整修改后的代码
const express = require('express'); const app = express(); const rendertron = require('rendertron-middleware'); const PORT = process.env.PORT || 8080; const fetch = require('node-fetch'); const https = require('https'); const httpsAgent = new https.Agent({ rejectUnauthorized: false, }); const bots = [ 'googlebot', 'baiduspider', 'bingbot', 'embedly', 'facebookexternalhit', 'linkedinbot', 'outbrain', 'pinterest', 'quora link preview', 'rogerbot', 'showyoubot', 'slackbot', 'twitterbot', 'vkShare', 'W3C_Validator', 'whatsapp', ]; const BOT_UA_PATTERN = new RegExp(bots.join('|'), 'i'); // 解析POST/PUT等请求的body app.use(express.json()); app.use(express.urlencoded({ extended: true })); // Rendertron中间件:仅处理Bot请求 app.use(rendertron.makeMiddleware({ proxyUrl: 'https://render-tron.appspot.com/render', userAgentPattern: BOT_UA_PATTERN, injectShadyDom: true })); // 转发所有非Bot请求到原Angular应用 app.all('*', async (req, res) => { res.set('Vary', 'User-Agent'); try { // 拼接目标地址:原应用地址 + 用户请求的路径 const targetUrl = `https://kitten-corner.glitch.me${req.path}`; // 构建fetch选项:传递原请求的方法、headers、body const fetchOptions = { method: req.method, agent: httpsAgent, headers: { // 复制原请求headers,排除host等可能冲突的字段 ...req.headers, host: new URL('https://kitten-corner.glitch.me').host }, // 非GET请求传递body body: req.method !== 'GET' ? JSON.stringify(req.body) : undefined }; // 请求原应用 const response = await fetch(targetUrl, fetchOptions); // 传递原应用的响应头 for (const [key, value] of response.headers.entries()) { res.setHeader(key, value); } // 设置响应状态码并返回响应体 res.status(response.status); const body = await response.text(); res.send(body); } catch (error) { console.error('转发请求失败:', error); res.status(500).send('服务器内部错误'); } }); app.listen(PORT, (error) => { if (!error) { console.log(`服务器已启动,监听端口 ${PORT}`); } else { console.error('服务器启动失败:', error); } });
关键修改说明
app.all('*'):覆盖所有HTTP请求方法,确保POST/PUT等操作能转发到原应用。- 动态拼接
targetUrl:保留用户请求的路径,让原应用返回对应页面。 - 传递请求信息:复制原请求的headers、方法和body,保证原应用能正确处理请求。
- 传递响应信息:将原应用的响应头、状态码完整返回,确保页面样式、脚本等资源正常加载。
内容的提问来源于stack exchange,提问作者ScorprocS
相关产品推荐
相关产品推荐

