【问题标题】:HTTP Interceptor doesn't complete (i.e. finalize is never called)HTTP 拦截器未完成(即永远不会调用 finalize)
【发布时间】:2021-08-25 02:07:29
【问题描述】:

在我的 Angular 8 项目中,我实现了最简单的 HttpInterceptor,它只是传递请求,而不做任何操作

在我的 Angular 8 项目中,我实现了一个简单的 HttpInterceptor,它只是克隆了原始请求并添加了一个参数:

@Injectable()
export class RequestHeadersInterceptor implements HttpInterceptor {

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // original code return next.handle(request) // pass-by request as-is

    return next.handle(request.clone({
      params: request.params.set('language', 'en') }
    ));
  }
}

然后,在我的服务中,我有一个 getFoos() 方法,它发出一个 HTTP 调用,该调用将被 RequestHeadersInterceptor 拦截:

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { finalize } from 'rxjs/operators';
import { Foo } from '.';

@Injectable({
  providedIn: 'root'
})
export class FooService {
  constructor(private http: HttpClient) { }

  getFoos() {
    return this.http.get<Foo[]>('/foos')
      .pipe(
        finalize(() => console.log('observable completed!'))
      );
  }
}

在我的组件中我终于订阅了getFoos()

fooService.getFoos().subscribe(console.log);

预期输出

[{ foo: 1 }, { foo: 2 }]
observable completed!

实际输出

[{ foo: 1 }, { foo: 2 }]

如您所见,finalize 永远不会被触发。这是为什么呢?

备注

  • 如果拦截器被移除,finalize 被触发,这是两种场景的预期行为
  • 我如何为模块提供拦截器:
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { RequestHeadersInterceptor } from './shared/http-requests';

@NgModule({
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: RequestHeadersInterceptor, multi: true },
  ]
);
  • 我更新了拦截器代码,因为我错误地指出,即使按原样传递请求,问题仍然存在。相反,它需要被克隆和更改。

  • 我添加了一个演示,基于 @PierreDuc 的演示(主要道具!)。但是,我无法在the demo 中重现该问题。这可能与某些请求或响应标头有关。

实时系统 API 上的响应标头

Cache-Control: no-store, no-cache, must-revalidate, max-age=0 Cache-Control: post-check=0, pre-check=0
Cache-Control: no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0
Connection: keep-alive
Content-Language: en-US
Content-Length: 42
Content-Type: application/json;charset=utf-8
Date: Tue, 21 Jan 2020 15:44:33 GMT
Pragma: no-cache
Pragma: no-cache
Server: nginx/1.16.1
X-Content-Type-Options: nosniff
X-Powered-By: Servlet/3.1

实时系统 API 上的请求标头

Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Authorization: Basic xyzABC123
Cache-Control: no-cache
Connection: keep-alive
Content-Type: application/json
Cookie: check=true; anotherCookie=1; bla=2;
Host: some.page.com:11001
Pragma: no-cache
Referer: https://some.page.com
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36

【问题讨论】:

  • 你所拥有的看起来不错。问题可能出在其他地方。否则制作一个复制相同问题的演示。
  • 你是如何在 ngmodule 中提供拦截器的?
  • 你能分享一下初始化拦截器的代码吗?
  • 当您的 http 请求响应时,并不意味着您的 observable 完成了。那里的问题是您的 observable 根本没有完成。尝试将take(1) 放在finalize() 之前。如何在 RxJS 中完成 Observable? stackoverflow.com/questions/34097158/…
  • @Ronin 我创建了一个stackblitz,但我没有得到你的结果。所以我猜这个问题缺少一些关于问题可能是什么的信息。你在哪里提供拦截器?

标签: angular typescript rxjs angular-http-interceptors


【解决方案1】:

“问题”是Connection: Keep-Alive 标头。这会保持一个打开的连接

Connection 通用标头控制当前事务完成后网络连接是否保持打开状态。如果发送的值是 keep-alive,则连接是持久的并且不会关闭,从而允许完成对同一服务器的后续请求。

这将导致 Observable 不完整,直到连接终止。

因此,这并不是您真正的错误或问题。我猜在您的HttpInterceptor 中添加了此标头,所以这就是它仅在您添加拦截器后才引起的原因

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-02
    • 2013-06-18
    • 1970-01-01
    • 2020-12-22
    • 2013-12-14
    • 2016-07-13
    相关资源
    最近更新 更多