我正在用TypeScript开发一个homebridge插件,并使用axios处理网络请求(GitHub link).该插件登录本地网络中的服务器一次,然后定期轮询服务器以获取服务器的状态信息。如果会话过期,服务器将返回302错误并重定向到登录页面。因此插件不允许重定向,并在重试实际请求之前查找30 x错误,这意味着需要再次登录并更新会话。我使用一个助手函数来进行实际的网络请求,并且对该函数的每个调用都被 Package 在try { await...} catch { }块中。无论如何,偶尔会有一个错误跳过错误处理机制并传播回主事件循环,在那里它会导致插件崩溃,因为它没有得到处理。
相关代码如下:
在类构造函数中:
// [...]
this.client = axios.create({
baseURL: this.httpPrefix + this.IPAddress,
timeout: 10000,
maxRedirects: 0,
method: "post",
headers: {
'content-type': 'application/x-www-form-urlencoded'
}
});
// [...]
在轮询功能中:
[...]
try {
const response = await this.makeRequest('user/seq.xml', {'sess': this.sessionID});
// [...]
} catch (error) { throw(error); }
处理请求的实际helper函数:
private async makeRequest(address: string, payload = {}) {
try {
return await this.client({
url: address,
data: payload
});
} catch (error) {
if (axios.isAxiosError(error)) {
const response = error.response;
if (response == undefined) throw error;
if (response.status >= 300 && response.status < 400) {
await this.login();
payload['sess'] = this.sessionID;
const response = await this.client({
url: address,
data: payload
});
return response;
} else throw(error);
} else throw (error);
}
}
下面这个函数负责按固定时间间隔调度轮询:
async updateAccessories() {
// [...]
try {
await this.securitySystem.poll();
// [...]
} catch (error) {
this.log.error((<Error>error).message);
await delay(retryDelayDuration);
}
setTimeout(this.updateAccessories.bind(this), this.pollTimer);
}
上面调用的delay函数是一个小助手,如下所示:
export function delay(milliseconds: number) {
return new Promise(resolve => setTimeout(resolve, milliseconds));
}
本质上,homebridge服务器加载插件,在初始登录和附件发现之后,插件第一次调用updateAccessories函数,并且它自己将使用setTimeout来重新安排自己在pollTimer间隔之后再次运行。poll(),然后执行所有必要的逻辑来查询服务器、检索并解析所有相关数据以及更新数据模型,其思想是,如果一个轮询由于任何原因失败,插件应该优雅地掩盖它,并在下一次轮询尝试时重试。
您可以看到每个axios请求都是用await调用的,并被 Package 在try/catch块中以检查30个错误,helper函数本身也是用类似的机制调用的。理论上,所有的错误都应该被捕获并在程序逻辑的更高层处理。然而,我却遇到了这样的间歇性错误:
AxiosError: Request failed with status code 302
at settle (/usr/lib/node_modules/homebridge-caddx-interlogix/node_modules/axios/lib/core/settle.js:19:12)
at IncomingMessage.handleStreamEnd (/usr/lib/node_modules/homebridge-caddx-interlogix/node_modules/axios/lib/adapters/http.js:495:11)
at IncomingMessage.emit (node:events:525:35)
at endReadableNT (node:internal/streams/readable:1358:12)
at processTicksAndRejections (node:internal/process/task_queues:83:21)
看起来好像一些axios失败的调用最终逃脱了错误处理,并进入了主事件循环,因此使程序崩溃。我做了一些搜索,并确保setTimeout代码是在try/catches之外调用的,但仍然经常出现错误。
有什么想法吗?先谢谢了。
1条答案
按热度按时间pxyaymoc1#
更新:我没有设法实际阻止程序执行期间发生未捕获的302错误,但我用另一种方法解决了这个问题:我在类构造函数中为创建客户机对象添加了一个validateStatus选项:
这部分代码与maxRedirects结合使用:0使axios不遵循302重定向,但不认为它们是错误,这给了我机会在helper函数中手动处理这些状态代码,检查response.status值。只是把这个留给可能需要类似这样的东西的人:)