如何处理axios.all请求失败?跳过故障服务器保留有效数据
如何处理axios.all中的单个请求失败并保留有效数据
这个问题很常见——axios.all(本质是原生Promise.all的封装)会在数组中任何一个Promise被reject时立即终止流程,直接进入catch块,导致你完全拿不到其他成功请求的数据,最终写入空文件。
解决思路很简单:给每个单独的请求添加错误处理,让它们即使失败也不会reject,而是返回一个包含错误信息的「安全」结果。这样axios.all就能正常处理所有结果,你可以在then回调里过滤出成功的数据,同时记录失败的情况。
下面是修改后的完整代码,我标注了关键改动:
var fs = require("fs"); var axios = require('axios'); var util = require('util'); var round = 0; var tmp = {}; var streem = fs.createWriteStream(__dirname + '/data.json', {flags : 'w'}); toFile = function(d) { streem.write(util.format(d)); }; start(); setInterval(start, 27000); function start(){ streem = fs.createWriteStream(__dirname + '/data.json', {flags : 'w'}); monitor(); } function monitor(){ // 关键改动:给每个axios请求单独添加catch,返回包含来源和错误的对象 axios.all([ axios.get('server1:api') .then(res => ({ source: 'server1', data: res.data })) .catch(err => { let errorMsg = `请求失败: ${err.message}`; // 处理非JSON响应/无响应的情况,补充详细信息 if (err.response) { errorMsg += `,状态码:${err.response.status}`; if (err.response.data) { errorMsg += `,响应内容:${String(err.response.data).slice(0, 100)}`; // 截断长内容避免日志溢出 } } return { source: 'server1', error: errorMsg }; }), axios.get('server2:api') .then(res => ({ source: 'server2', data: res.data })) .catch(err => { let errorMsg = `请求失败: ${err.message}`; if (err.response) { errorMsg += `,状态码:${err.response.status}`; if (err.response.data) { errorMsg += `,响应内容:${String(err.response.data).slice(0, 100)}`; } } return { source: 'server2', error: errorMsg }; }), axios.get('server3:api') .then(res => ({ source: 'server3', data: res.data })) .catch(err => { let errorMsg = `请求失败: ${err.message}`; if (err.response) { errorMsg += `,状态码:${err.response.status}`; if (err.response.data) { errorMsg += `,响应内容:${String(err.response.data).slice(0, 100)}`; } } return { source: 'server3', error: errorMsg }; }), axios.get('server4:api') .then(res => ({ source: 'server4', data: res.data })) .catch(err => { let errorMsg = `请求失败: ${err.message}`; if (err.response) { errorMsg += `,状态码:${err.response.status}`; if (err.response.data) { errorMsg += `,响应内容:${String(err.response.data).slice(0, 100)}`; } } return { source: 'server4', error: errorMsg }; }), ]).then((responses) => { tmp.servers = {}; // 遍历所有响应,分别处理成功和失败的情况 responses.forEach(res => { if (res.error) { console.error(`[Round ${round}] ${res.source} ${res.error}`); // 可以选择把失败信息存入文件,或者直接跳过 tmp.servers[res.source] = { status: 'failed', error: res.error }; } else { tmp.servers[res.source] = res.data; } }); toFile(JSON.stringify(tmp, null, 2)); // 格式化JSON让文件更易读 round++; streem.end(); streem.on('finish', () => { console.error(`Round: ${round} - 数据已写入`); }); }).catch(error => { // 现在这个catch只会捕获极罕见的全局异常(比如axios.all本身的bug) console.error('全局未捕获异常:', error); }); }
关键说明:
- 单个请求的错误隔离:每个
axios.get都通过.catch()返回一个包含错误信息的对象,而不是触发reject,这样axios.all就不会被中断。 - 区分成功/失败数据:在then回调里遍历所有响应,根据是否有
error字段来分别处理,既保留成功的JSON数据,也能记录失败的服务器信息。 - 详细错误日志:不仅记录错误消息,还会补充状态码和响应内容(截断避免日志过长),方便后续排查问题。
- 格式化JSON:写入文件时用
JSON.stringify(tmp, null, 2)让生成的data.json结构更清晰,便于查看。
另外提一句:现在更推荐直接用原生的Promise.all替代axios.all,用法完全一致,不需要依赖axios的这个封装方法。
内容的提问来源于stack exchange,提问作者MAx Shvedov
相关产品推荐
相关产品推荐

