Node.js批量获取多网页title并组装响应返回的实现问题
问题根源
你现在的代码核心问题是异步逻辑时序错误:axios发起的网络请求是非阻塞异步操作,Array.map遍历发起所有请求后会立刻往下执行,不等任何请求返回就已经运行到res.send()结束响应了,自然没法收集到所有title结果。
另外现有代码还有三个隐性bug:
parseTitle函数匹配不到title时,没有return错误提示字符串,会直接返回undefined- 传入的address如果没带
http/https协议前缀,axios会直接把地址当成本地路径请求,必然失败 - 原代码里的"Title Not FOund"存在拼写错误
修复代码
直接替换成下面的实现即可,支持多address参数、单地址失败不影响其他请求、自动补全协议、等所有请求完成后再渲染HTML返回:
const parseTitle = (body) => { let match = body.match(/<title>(.*?)<\/title>/); if (!match || typeof match[1] !== "string") return "Title Not Found"; return match[1]; }; app.get("/I/want/title/", async (req, res) => { const query = url.parse(req.url, true).query; if (!query.address) { return res.status(400).send("Missing url query parameter"); } const addressList = typeof query.address === "string" ? [query.address] : query.address; // 为每个地址构造独立请求任务,单任务失败不影响整体 const requestTasks = addressList.map(async (address) => { // 自动补全协议头,适配无协议的入参 const targetUrl = address.startsWith('http') ? address : `https://${address}`; try { const { data } = await axios.get(targetUrl, { timeout: 5000 }); return `${address} -- ${parseTitle(data)}`; } catch (error) { return `${address} -- NO RESPONSE`; } }); // 等待所有请求全部执行完成 const titleResults = await Promise.all(requestTasks); // 组装HTML响应 const responseHtml = ` <html> <head></head> <body> <h1>Following are the titles of given websites:</h1> <ul> ${titleResults.map(item => `<li>${item}</li>`).join('')} </ul> </body> </html> `; res.send(responseHtml); });
关键改动说明
- 路由处理函数改为async声明,用await等待所有异步请求执行完毕后再返回响应,解决提前发送响应的问题
Array.map遍历的时候直接返回每个请求的Promise实例,把所有Promise收集成数组交给Promise.all统一等待结果- 每个请求单独做try/catch异常捕获,单个地址请求失败、超时都不会打断其他请求,也不会导致接口报错
- 补全
parseTitle漏写的return逻辑,修正原代码里的拼写错误 - 新增协议头自动补全逻辑,兼容用户传入不带http/https的地址
- 给axios请求加5秒超时配置,避免请求长时间挂起占用服务资源
内容的提问来源于stack exchange,提问作者MuTanT46
相关产品推荐
相关产品推荐

