客户端JS/Angular中是否有HTTP连接超时?

3
我正在使用Angular的HttpClient来进行HTTP请求,我想为它们指定超时时间。
我知道可以使用HTTPInterceptors并向RxJS操作符添加超时,但是这些适用于整个请求,如果数据传输正在进行中,我不想中止整个请求,只有在浏览器尝试连接时挂起时才这样做。
例如,在Node.js中提供了我需要的超时类型,这在here中有很好的解释:
“假设您调用了socket.setTimeout(300)将超时设置为300 毫秒,DNS查找花费了100毫秒,与远程服务器建立连接花费了100毫秒, 远程服务器发送响应头花费了200毫秒,传输响应主体的前半部分花费了50毫秒, 另外50毫秒。虽然整个请求和响应的时间超过了500毫秒,但超时事件根本没有发生。”
是否可能在Angular应用程序中拥有这样的超时?
2个回答

3
我查看了HttpClient的源代码。实际处理底层XMLHttpRequest的代码是类HttpXhrBackend,在源文件xhr.ts中。
不幸的是,HttpXhrBackend只使用XMLHttpRequest的默认设置,并没有提供设置XMLHttpRequest超时值的方法。
我见过使用RxJS运算符缩短有效超时时间的建议,但那有点像hack,并不能真正做到你所要求的。
所以,从技术上讲,对于原始的Angular HttpClient,答案是“不行”,但我想你可以创建自己的HttpBackend实现并尝试注入它。
P.S. 这篇文章展示了如何提供自定义的HttpBackend实现。

为什么使用RxJS操作符会被认为是一种hack? - C.OG
1
在本身使用 RxJS 操作符并不是hack,但是试图通过简单地提前终止连接来缩短 XMLHttpRequest 的超时时间,就是我的个人看法下的hack。你的情况可能有所不同。 - GreyBeardedGeek
公平起见,您是否认为使用类似于AbortController的方法中止请求也是一种hack? - C.OG
@GreyBeardedGeek 感谢您的调查。我接受这个答案,因为我目前也没有看到合理的解决方案。我认为,通过扩展HttpClient或使用其他自定义实现可能会带来更多的缺点,所以我只是提出了一个功能请求 - tom

0
对于那些仍在寻找“hacky”解决方案的人,您可以创建一个observable,在所需的超时时间后插入一个空/失败对象。
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对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接