如何使用httpclient拦截角度jsonp请求

Posted

技术标签:

【中文标题】如何使用httpclient拦截角度jsonp请求【英文标题】:how to intercept angular jsonp requests using httpclient 【发布时间】:2017-11-30 12:35:18 【问题描述】:

我有一个用于 http get/post 请求的拦截器。效果很好。

不幸的是,它不适用于我的 jsonp 请求/它们没有被捕获。

因此我想创建另一个实现 JsonpInterceptor 的拦截器。

事实上,它也不起作用。

到目前为止我做了什么:

应用模块:

[ provide: HTTP_INTERCEPTORS, useClass: MyJsonpInterceptor, multi: true ],

MyJsonpInterceptor:

@Injectable()
export class MyJsonpInterceptor implements JsonpInterceptor 

    constructor(jsonp: JsonpClientBackend) 

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> 
        console.log("intercept");
    


有人知道,如何使用新的 httpclient 以 4/5 的角度拦截 jsonp 请求吗?

【问题讨论】:

【参考方案1】:

我认为角度方面的JsonpInterceptor 可能是关键点。这是我的解决方案:

    检查您的NgModule 配置,删除HttpClientJsonpModule。 然后将JsonpClientBackendprovide: ɵb, useFactory: ɵc 添加到providers.ɵb 和ɵc 是JsonpCallbackContextjsonpCallbackContext 的别名 然后添加provide: HTTP_INTERCEPTORS, useClass: JsonpInterceptor, multi: true, 作为最后一个HTTP_INTERCEPTORS。或者,您可以使用自定义拦截器覆盖 JsonpInterceptor。

希望对你有帮助。

2018.03.09 更新:

你可以这样做:

@NgModule(
  providers: [
     provide: HTTP_INTERCEPTORS, useClass: XxxInterceptor, multi: true ,
  ],
)
export class XxxModule 


@NgModule(
  declarations: [
  ],
  imports: [
    XxxModule,
    HttpClientJsonpModule,
  ],
  providers: [
    ...
  ],
  bootstrap: [AppComponent]
)
export class AppModule  

【讨论】:

你能解释一下 XxxModule 的派生 JsonpInterceptor 应该是什么样子吗?我总是收到这个错误:'Class 'AuthInterceptorService' incorrectly implements interface 'JsonpInterceptor'. Types have separate declarations of a private property 'jsonp'.implements(接口)和extends 尝试过。我认为extends 可能是合适的,因为 JsonpInterceptor 是一个类。我完全误解了什么吗?是否有可能从 Angular 的 JsonpInterceptor 派生并添加一些自定义逻辑,还是我们必须编写一些全新的东西? 啊,我现在明白了,我认为 JsonpInterceptor 不应该继承自。它只是一个完整且随时可用的拦截器来处理 JSONP 请求,仅此而已。与推送到 HTTP_INTERCEPTORS 多提供程序的其他拦截器一起使用(链接)。问题是这里的调用顺序。也许这就是你试图展示的?通过将 HttpClientJsonpModule 放在 XxxModule 之后,希望 jsonp 拦截器会在最后被调用。但是,这对我没有用。【参考方案2】:

你必须在HttpClientJsonpModule之前导入JSONP拦截模块

import  NgModule, Injectable  from '@angular/core';
import  BrowserModule  from '@angular/platform-browser';
import 
  HttpClient,
  HTTP_INTERCEPTORS,
  HttpEvent,
  HttpRequest,
  HttpHandler,
  HttpClientModule,
  HttpClientJsonpModule
   from '@angular/common/http'
import  Observable  from 'rxjs'
import  AppComponent  from './app.component';

@Injectable()
export class CustomInterceptor 
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> 
    return next.handle(req);
  


@NgModule(
  providers: [
     provide: HTTP_INTERCEPTORS, useClass: CustomInterceptor, multi: true
  ]
)
export class JsonpInterceptingModule 

@NgModule(
  imports:      [ 
    BrowserModule,
    JsonpInterceptingModule, // Must be before the HttpClientJsonpModule
    HttpClientModule,
    HttpClientJsonpModule
  ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ],
  providers: [
     provide: HTTP_INTERCEPTORS, multi: true, useClass: CustomInterceptor 
  ]
)
export class AppModule 
  constructor(http: HttpClient)
    http.jsonp('https://archive.org/index.php?output=json', 'callback')
      .subscribe(response => console.log(response));
  

【讨论】:

【参考方案3】:

我还是不知道怎么拦截jsonp请求。到现在为止,我认为它实际上并没有多大用处,因为 JSONP 请求是通过将脚本标记注入页面的 html 来发出的,请求的 URL 作为 src 参数。所以我认为不可能添加任何 HTTP 标头。也许这就是为什么 JsonpInterceptor 没有被设计为除了作为任何 JSONP 调用的独立工作之外,忽略随后出现的所有其他拦截器。

但我至少可以在一定程度上解释这个问题。也许其他人可以对此进行扩展以提供进一步的提示。

为了使http.jsonp 方法正常工作,通常只需导入HttpClientJsonpModule,它将JsonpInterceptor 提供给HTTP_INTERCEPTORS 令牌。 来自 Angular 文档的 HttpClientJsonpModule 注释:

@NgModule( providers: [ JsonpClientBackend, provide: JsonpCallbackContext, useFactory: jsonpCallbackContext , provide: HTTP_INTERCEPTORS, useClass: JsonpInterceptor, multi: true , ] )

JsonpInterceptor 是一个实现HttpInterceptor 接口的类。 JsonpInterceptor 不是一个接口(所以你不应该implement 它,我认为),它显然也不是为了派生和扩展而设计的。它是一个可注入的 Angular 服务,它需要一个提供者和它周围的其他东西才能工作。这东西都是捆绑在HttpClientJsonpModule里面的,在导入HttpClientJsonpModule的上下文之外,直接使用JsonpInterceptor的用例可能不多。

HTTP_INTERCEPTORS 注入令牌可以分配多个拦截器。然后这些都依次应用于每个请求。 通过诸如 [ provide: HTTP_INTERCEPTORS, useClass: MyCustomInterceptor, multi: true ], 您只需将另一个拦截器添加到链中。

但顺序可能很重要。

JsonpInterceptor 将在遇到 JSONP 类型的请求时结束拦截器链。在这种情况下,不会调用它之​​后的所有拦截器。所以只有对非 JSONP 的请求才会通过其他拦截器。

因此,最好确保在来自HttpClientJsonpModule 的 JsonpInterceptor 之前提供所有其他拦截器。

很遗憾,我仍然没有找到方法。

但是拦截 JSONP 请求还有另一个问题。这就是事实,JSONP 实际上只是一种标准化的“黑客”,可以在浏览器中发出绕过 CORS 安全检查的请求。 为了发出请求,在页面中插入一个javascript标签,请求的url为src参数,以获取加载的内容。 我认为不可能为这样的请求设置任何标头。所以这可能是 JsonpInterceptor 总是结束拦截器链的原因。另一个可能是链之后的“最后一次调用”,它会发出实际的请求,不知道它应该通过向页面中注入标签来完成,但总是只会做一个正常的请求。

【讨论】:

以上是关于如何使用httpclient拦截角度jsonp请求的主要内容,如果未能解决你的问题,请参考以下文章

若不用jsonp,可使用httpClient请求数据

使用Httpclient 完美解决服务端跨域问题

Angular:如何扩展 HttpClient?

如何使用标头、有效负载和正文制作 httpclient 获取请求?角度 API

如何使用角度 4.3 中的新 httpClient 处理未经授权的请求(状态为 401 或 403)

JSONP和HttpClient的区别