客户端 JS/Angular 中是否存在 HTTP 连接超时?
Is there an HTTP Connection Timeout in client-side JS/Angular?
我正在使用 Angular 的 HttpClient 发出 HTTP 请求,我想为它们指定一个超时。
我知道我可以使用 HTTPInterceptors 并为 RxJS 运算符添加超时,但是,这些适用于整个请求,如果数据传输正在进行,我不想中止,只有当浏览器在尝试时挂起连接。
例如,Node.js 中提供了我需要的那种超时,这很好地解释了 here:
Let's say you called socket.setTimeout(300)
to set the timeout as 300
ms, and it took 100 ms for DNS lookup, 100 ms for making a connection
with a remote server, 200 ms for the remote server to send response
headers, 50 ms for transferring the first half of the response body
and another 50 ms for the rest. While the entire request & response
took more than 500 ms, timeout event is not emitted at all.
是否可以在 Angular 应用程序中设置这样的超时?
我查看了 HttpClient 的源代码。实际处理底层 XMLHttpRequest 的代码是 class HttpXhrBackend,在名为 xhr.ts
的源文件中
遗憾的是,HttpXhrBackend 只是使用 XMLHttpRequest 的默认设置,并没有提供设置 XMLHttpRequest 超时值的方法。
我看到了使用 RxJS 操作符来缩短有效超时的建议,
但这有点 hack,并没有真正满足您的要求。
因此,从技术上讲,您的问题的答案是 "No",而不是现有的 Angular HttpClient,但我想您可以创建自己的 HttpBackend 实现并尝试注入它。
P.S。 This article 展示了如何提供自定义 HttpBackend 实现。
对于那些仍在寻求 'hacky' 解决方案的人,您可以创建一个可观察对象并在所需的超时期限后插入一个 empty/failure:
handleError(error: HttpErrorResponse) {
console.warn('HTTPErrorResponse caught', error);
return observableOf({});
}
async __sendCommandHTTP(cmd: SoftAPCommand) {
const URL = this.options.host + cmd.name;
let result: SoftAPResponse = {
name: cmd.name,
payload: {},
error: false,
};
this.logger.debug('[softap-setup starting request');
await new Promise(resolve => {
const httpEvent: Subject<any> = new Subject<any>();
let returned = false;
const sub = this.http
.get<any>(URL, {})
.pipe(catchError(this.handleError))
.subscribe(data => httpEvent.next(data));
// Our cheeky method to ensure a timeout
setTimeout(async () => {
if (!returned) {
this.logger.info('[softap-setup] timeout on ' + result.name);
httpEvent.next({});
}
}, 5000);
httpEvent.subscribe(data => {
this.logger.info('[softap-setup] response ', data);
returned = true;
switch (cmd.name) {
case 'scan-ap':
if (Object.prototype.hasOwnProperty.call(data, 'scans') && data.scans.length) {
result.payload = data.scans;
} else {
result.error = true;
}
break;
default:
result.payload = data;
break;
}
httpEvent.complete();
resolve();
});
});
return result;
}
基本上响应或超时标志都有结果。 handleError 函数还巧妙地处理可能出现的任何最终错误,即主机不可用。您可以在其中应用其他逻辑,甚至可以传递 HTTPErrorResponse 对象。
我正在使用 Angular 的 HttpClient 发出 HTTP 请求,我想为它们指定一个超时。
我知道我可以使用 HTTPInterceptors 并为 RxJS 运算符添加超时,但是,这些适用于整个请求,如果数据传输正在进行,我不想中止,只有当浏览器在尝试时挂起连接。
例如,Node.js 中提供了我需要的那种超时,这很好地解释了 here:
Let's say you called
socket.setTimeout(300)
to set the timeout as 300 ms, and it took 100 ms for DNS lookup, 100 ms for making a connection with a remote server, 200 ms for the remote server to send response headers, 50 ms for transferring the first half of the response body and another 50 ms for the rest. While the entire request & response took more than 500 ms, timeout event is not emitted at all.
是否可以在 Angular 应用程序中设置这样的超时?
我查看了 HttpClient 的源代码。实际处理底层 XMLHttpRequest 的代码是 class HttpXhrBackend,在名为 xhr.ts
的源文件中遗憾的是,HttpXhrBackend 只是使用 XMLHttpRequest 的默认设置,并没有提供设置 XMLHttpRequest 超时值的方法。
我看到了使用 RxJS 操作符来缩短有效超时的建议, 但这有点 hack,并没有真正满足您的要求。
因此,从技术上讲,您的问题的答案是 "No",而不是现有的 Angular HttpClient,但我想您可以创建自己的 HttpBackend 实现并尝试注入它。
P.S。 This article 展示了如何提供自定义 HttpBackend 实现。
对于那些仍在寻求 'hacky' 解决方案的人,您可以创建一个可观察对象并在所需的超时期限后插入一个 empty/failure:
handleError(error: HttpErrorResponse) {
console.warn('HTTPErrorResponse caught', error);
return observableOf({});
}
async __sendCommandHTTP(cmd: SoftAPCommand) {
const URL = this.options.host + cmd.name;
let result: SoftAPResponse = {
name: cmd.name,
payload: {},
error: false,
};
this.logger.debug('[softap-setup starting request');
await new Promise(resolve => {
const httpEvent: Subject<any> = new Subject<any>();
let returned = false;
const sub = this.http
.get<any>(URL, {})
.pipe(catchError(this.handleError))
.subscribe(data => httpEvent.next(data));
// Our cheeky method to ensure a timeout
setTimeout(async () => {
if (!returned) {
this.logger.info('[softap-setup] timeout on ' + result.name);
httpEvent.next({});
}
}, 5000);
httpEvent.subscribe(data => {
this.logger.info('[softap-setup] response ', data);
returned = true;
switch (cmd.name) {
case 'scan-ap':
if (Object.prototype.hasOwnProperty.call(data, 'scans') && data.scans.length) {
result.payload = data.scans;
} else {
result.error = true;
}
break;
default:
result.payload = data;
break;
}
httpEvent.complete();
resolve();
});
});
return result;
}
基本上响应或超时标志都有结果。 handleError 函数还巧妙地处理可能出现的任何最终错误,即主机不可用。您可以在其中应用其他逻辑,甚至可以传递 HTTPErrorResponse 对象。