【问题标题】:Extend HTTP - Redirect when returns unauthorized扩展 HTTP - 未经授权返回时重定向
【发布时间】:2016-09-15 14:08:43
【问题描述】:

当我获得 401 http 状态时,我正尝试重定向到登录页面。 拳头尝试是:

public getPatients(extraHttpRequestParams?: any): Observable<Array<models.Patient>> {
const path = this.basePath + '/api/patient';

let queryParameters = new URLSearchParams();
let headerParams = this.defaultHeaders;
let requestOptions: RequestOptionsArgs = {
    method: 'GET',
    headers: headerParams,
    search: queryParameters
};

return this.httpInterceptor.request(path, requestOptions)
    .map((response: Response) => {
        if (response.status === 204) {
            return undefined;
        } else {
            if (response.status === 401) {
                this.router.navigate(['/login']);
            }
            return response.json();
        }
    });

}

但是当我得到401时,我没有进入地图功能,它在浏览器中给出了一个未经授权的错误。

所以阅读一些帖子,有一种扩展http服务的方法,似乎是正确的方法,但是当我尝试在app.module.ts上实例化http依赖时遇到了一些问题。就我而言,我只需要重写拦截器方法,但是如果其他人需要其他部分,我会放所有代码。

这是我的 http 扩展:

import { Http, Request, RequestOptionsArgs, Response, XHRBackend, RequestOptions, ConnectionBackend, Headers} from '@angular/http';
import { Router } from '@angular/router';
import { LocationStrategy, HashLocationStrategy} from '@angular/common';
import { Observable } from 'rxjs/Observable';
import {Injectable} from '@angular/core';

@Injectable()
export class HttpInterceptor extends Http {

    constructor(backend: ConnectionBackend, defaultOptions: RequestOptions, private _router: Router) {
        super(backend, defaultOptions);
    };

    request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.request(url, options));
    };

    get(url: string, options?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.get(url, options));
    };

    post(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.post(url, body, this.getRequestOptionArgs(options)));
    };

    put(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.put(url, body, this.getRequestOptionArgs(options)));
    };

    delete(url: string, options?: RequestOptionsArgs): Observable<Response> {
        return this.intercept(super.delete(url, options));
    };

    getRequestOptionArgs(options?: RequestOptionsArgs): RequestOptionsArgs {
        if (options == null) {
            options = new RequestOptions();
        }
        if (options.headers == null) {
            options.headers = new Headers();
        }
        options.headers.append('Content-Type', 'application/json');
        return options;
    };

    intercept(observable: Observable<Response>): Observable<Response> {
        return observable.catch((err, source) => {
            if (err.status == 401) {
                this._router.navigate(['/login']);
                return Observable.empty();
            } else {
                return Observable.throw(err);
            }
        });

    }
};

在我的 app.module.ts 我必须添加这个:

import { NgModule } from '@angular/core';
import { BrowserModule }  from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { routing, appRoutingProviders } from './app.routing';
import { FormsModule }    from '@angular/forms';
import { Routes, RouterModule }   from '@angular/router';
import { HomeComponent } from './home/home.component';
import { PatientsComponent } from './pacientes/pacientes.component';
import { HttpInterceptor }  from '../api/api/HttpInterceptor';
import { RequestOptions, ConnectionBackend} from '@angular/http';
import { HttpModule, JsonpModule } from '@angular/http';
const routes: Routes = [

];

@NgModule({
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    JsonpModule,
    routing,
    RouterModule.forRoot(routes, { useHash: true }),  // .../#/crisis-center/
  ],
  declarations: [
    AppComponent,
    PatientsComponent,
  ],
  providers: [
    appRoutingProviders,
    HttpInterceptor,
    RequestOptions 
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

现在一切都好,但是当我尝试使用我创建的新 httpInterceptor 服务时,将其导入并将其添加到构造函数并为我的新 http 拦截器实例替换 http 实例,我得到 ConnectionBackend 的 No provider,我尝试将 ConnectionBackend 添加到提供程序,但它说“属性提供程序的类型不兼容”。然后我尝试添加 httpInterceptor 但我得到 Uncaught Error: Can't resolve all parameters for RequestOptions: (?).

所以总而言之,必须有一种方法可以正确扩展http方法或以另一种方式处理401.. 我该怎么做,有一些教程,链接或其他东西可以看看吗?

【问题讨论】:

  • 你使用的是什么 Angular 版本?
  • 我使用的是rc6版本

标签: angular angular2-services angular2-http


【解决方案1】:

没有使用令牌ConnectionBackend 注册的提供程序。你可以做的是在配置拦截器时使用工厂

providers:    [
  { 
    provide: HttpInterceptor,
    useFactory: (backend: XHRBackend, options: RequestOptions, router: Router) => {
      return new HttpInterceptor(backend, options, router);
    },
    deps: [XHRBackend, RequestOptions, Router ]
  }
]

我已经用你的代码对此进行了测试,它应该可以工作。

【讨论】:

  • 我正在使用 http 发出请求,但我必须实例化这个新的 http HttpInterceptor 而不是 this.http.request... 我使用 this.http.httpInterceptor。我认为使用该工厂不需要为我的 HttpInterceptor 替换 http,它只会使用它。有什么方法可以不替换并告诉 Angular 始终使用我的 HttpInterceptor?
  • 使用provide: Http
  • 如果仍然不行(它仍然使用普通的 Http),那么你可能需要摆脱 HttpModule 导入,并自己提供 Http 依赖的所有依赖项.可以查看HttpModule的源码
  • 你不是要使用Http,而不是HttpInterceptor吗? provide 提供您可以注入的 token。如果将其更改为Http,则无法再注入HttpInterceptor。但实际的 Http 对象仍然应该是您的自定义拦截器,因为这是您从工厂返回的内容
  • 确保您没有尝试在任何地方注入HttpInterceptor。你应该只尝试注入Http
猜你喜欢
  • 1970-01-01
  • 2018-10-21
  • 1970-01-01
  • 1970-01-01
  • 2013-08-24
  • 2016-04-18
  • 1970-01-01
  • 2023-03-09
  • 2018-11-05
相关资源
最近更新 更多