【问题标题】:Is there an HTTP Connection Timeout in client-side JS/Angular?客户端 JS/Angular 中是否存在 HTTP 连接超时?
【发布时间】:2020-04-08 10:29:18
【问题描述】:

我正在使用 Angular 的 HttpClient 发出 HTTP 请求,我想为它们指定超时时间。

我知道我可以使用 HTTPInterceptors 并向 RxJS 运算符添加超时,但是,这些适用于整个请求,如果数据传输正在进行,我不想中止,只有当浏览器在尝试连接时挂起时.

例如,我需要的那种超时可以在 Node.js 中得到很好的解释 here:

假设您调用socket.setTimeout(300) 将超时设置为 300 毫秒,DNS 查找需要 100 毫秒,建立连接需要 100 毫秒 使用远程服务器,远程服务器发送响应需要 200 毫秒 标头,50 ms 用于传输响应正文的前半部分 其余 50 毫秒。虽然整个请求和响应 耗时超过 500 毫秒,根本没有发出超时事件。

在 Angular 应用程序中是否可以有这样的超时?

【问题讨论】:

    标签: javascript angular http timeout


    【解决方案1】:

    对于那些仍在寻求“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 对象。

    【讨论】:

      【解决方案2】:

      我查看了 HttpClient 的源代码。实际处理底层 XMLHttpRequest 的代码是类 HttpXhrBackend,在名为 xhr.ts 的源文件中

      很遗憾,HttpXhrBackend 只是使用了 XMLHttpRequest 的默认设置,并没有提供设置 XMLHttpRequest 超时值的方法。

      我看到了使用 RxJS 运算符来缩短有效超时的建议, 但这有点小题大做,并不能真正满足您的要求。

      因此,从技术上讲,您的问题的答案是“否”,而不是使用股票 Angular HttpClient,但我想您可以创建自己的 HttpBackend 实现并尝试注入它。

      附: This article 展示了如何提供自定义 HttpBackend 实现。

      【讨论】:

      • 为什么使用 RxJS 操作符会被认为是 hack
      • 使用 RxJS 操作符本身并不是一种 hack,但是试图通过简单地提前终止连接来缩短 XMLHttpRequest 的超时时间,恕我直言,这是一种 hack。 YMMV
      • 公平,您是否还会将中止请求归类为 AbortController 黑客?
      • @GreyBeardedGeek 感谢您的调查。我接受这个作为答案,因为我现在也没有看到合理的解决方案。我认为以某种方式扩展 HttpClient 或使用其他一些自定义实现会有更多的缺点,所以我只是做了一个feature request
      猜你喜欢
      • 2023-04-02
      • 1970-01-01
      • 2019-03-07
      • 1970-01-01
      • 2019-03-23
      • 1970-01-01
      • 2011-04-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多