我使用Angular 2.4.8。与后端的通信是通过REST进行的。在每个请求中,我需要在标头中发送X-Auth-Token
。令牌存储在会话中。令牌过期时,服务器返回401状态。在这种情况下,我希望应用程序进入登录页面。
我在项目中添加了http拦截器
@Injectable()
export class HttpInterceptor extends Http {
constructor(backend: XHRBackend
, defaultOptions: RequestOptions
, private router: Router
) {
super(backend, defaultOptions);
}
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
return super.request(url, options).catch((error: Response) => {
if ((error.status === 401 || error.status === 403) &&
(window.location.href.match(/\?/g) || []).length < 2) {
// tslint:disable-next-line:no-console
console.log('The authentication session expires.');
window.sessionStorage.removeItem('auth-token');
window.location.href = window.location.href + '/login';
// this.router.navigate(['/login']);
return Observable.empty();
}
return Observable.throw(error);
});
}
}
除了以外它运作良好。但我不使用路由器,而是简单的重定向和整个应用程序重新加载。当我将评论改为
时// window.location.href = window.location.href + '/login';
this.router.navigate(['/login']);
该应用不会关注该链接。如何使路由器工作(导航)?
编辑2018-01-22
我的app-routing.module.ts
const routes: Routes = [
{
path: 'login',
component: LoginComponent,
resolve: {
boolean: InitResolverService
}
},
{
path: '**',
redirectTo: 'system'
}
];
@NgModule({
imports: [
RouterModule.forRoot(
routes
// , { enableTracing: true } // <-- debugging purposes only
)
],
exports: [
RouterModule
]
})
export class AppRoutingModule { }
在InitResolverService
中我在第一次导航时有一些逻辑,然后发出true
并完成流。
LoginComponent
@Component({
selector: 'app-login',
templateUrl: 'login.component.html',
styleUrls: ['login.component.less']
})
export class LoginComponent implements OnInit {
private username: FormControl;
private password: FormControl;
public form: FormGroup;
public displayDialog = false;
isLoginButtonEnabled = true;
isResetButtonVisible = false;
constructor(
private authService: AuthenticationService,
private router: Router,
private route: ActivatedRoute,
private initService: InitResolverService
) {
this.username = new FormControl(Validators.required);
this.password = new FormControl(Validators.required);
this.form = new FormGroup({
Username: this.username,
Password: this.password
});
this.form.setValue({
Username: '',
Password: ''
});
this.displayDialog = true;
}
ngOnInit() {
this.initService.showSplash();
this.authService.canActivate(this.route.snapshot, this.router.routerState.snapshot).subscribe(x => {
if (x) {
this.router.navigate(['/']);
}
});
}
}
答案 0 :(得分:4)
我们通过编写自己的自定义http服务来解决这种情况,我们通过REST使用所有http请求。
您也可以使用自定义http服务;
简单代码示例
import { Injectable } from '@angular/core';
import { Http, Response, Headers } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { ErrorObservable } from 'rxjs/observable/ErrorObservable';
export const API_PATH = "http://apipath"
@Injectable()
export class CustomHttpService {
constructor(
private http: Http,
public router: Router) { }
headerWithToken(): Headers {
const headers = new Headers();
headers.set('Authorization', 'bearer ' + localStorage.getItem('TOKEN'));
headers.set('Content-Type', 'application/json');
return headers;
}
get(params: URLSearchParams, method: string): Observable<any> {
const url = `${API_PATH}/${method}`;
return this.http.get(url, {params: params, headers: this.headerWithToken()})
.map(
res => <Array<any>>res.json()
)
.catch(err => {
const result = this.handleErrors(err, this);
return result;
});
}
// put same way
// post same way
// delete same way
public handleErrors(error: Response, obj: any): ErrorObservable {
const errData = error.json();
if (error.status === 401) {
obj.router.navigate(['/login']);
} else if (errData.message) {
// give a message or something
} else {
console.log(errData);
}
return Observable.throw(error.json());
}
}
答案 1 :(得分:2)
我没有使用拦截器。对于每个API调用,我使用.catch
来捕获错误并传递给此函数:
// define the error handler in a separate method so we can reuse it
//in other methods
private handleError(error: HttpErrorResponse | any) {
console.error('ApiService::handleError', error);
if (error.status === 401) {
this.oAuthService.logOut();
}
return Observable.throw(error);
}
希望这会有所帮助。
答案 2 :(得分:1)
此代码对我有用:
@Injectable()
export class JwtInterceptor implements HttpInterceptor {
constructor( public auth: AuthenticationService,
private router: Router ) {
}
public intercept( request: HttpRequest<any>, next: HttpHandler ): Observable<HttpEvent<any>> {
let url: string = request.url;
let method: string = request.method;
console.log(`JwtInterceptor url=${url}, method=${method}`);
return next.handle( request ).do( ( event: HttpEvent<any> ) => {
console.log(`successful reply from the server for request=${request.urlWithParams}`);
})
.catch((responseError: any) => {
// ResponseError Interceptor
if (responseError instanceof HttpErrorResponse) {
console.error('response in the catch: ', responseError);
if ( responseError.status === 401 ) {
let errorMsg: string = '';
if ( responseError.statusText === 'Invalid credentials' ) {
errorMsg = 'Username or password is incorrect';
}
// redirect to the login route
this.router.navigate(['/login'], {queryParams: {msg: errorMsg}});
return empty();
}
return throwError(responseError);
}
let error = new HttpErrorResponse({
status: 500,
statusText: 'Unknown Error',
error: {
message: 'Unknown Error'
}
});
return throwError( error );
}) as any;
}
}
答案 3 :(得分:-1)
在你的app.module.ts上你应该添加:
{provide : Http, useFactory: (xhrBackend: XHRBackend, requestOptions: RequestOptions, router: Router) => new HttpInterceptor(xhrBackend, requestOptions, router),deps: [XHRBackend, RequestOptions, Router]}
在你的HttpInterceptor:
constructor(backend: ConnectionBackend, defaultOptions: RequestOptions, private _router: Router) {
super(backend, defaultOptions);
}