HTTP_INTERCEPTOR在生产模式下未被调用(heroku)



我在heroku上部署了一个配置了HTTP_INTERCEPTORS的应用程序。应用的后端是在Spring框架中,部署在另一个heroku存储库中,而前端是Angular。

拦截器用于拦截请求并刷新报头中的jwttoken。

我写了一个简单的console.log("httpRequest intercepted", req)来检查拦截方法是否被触发。

对我来说奇怪的是它在本地启动时被正确调用,但在heroku上却没有。因此,jwtToken永远不会刷新并过期。

其他功能(登录,注册,连接到DB等)工作正常

你能看到我没看到的东西吗?

token-interceptor.ts

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http';
import { Observable, BehaviorSubject, throwError } from 'rxjs';
import { AuthService } from './auth/shared/auth.service';
import { catchError, switchMap, take, filter } from 'rxjs/operators';
import { LoginResponse } from './auth/login/login-response.payload';
@Injectable({
providedIn: 'root'
})
export class TokenInterceptor implements HttpInterceptor {
isTokenRefreshing = false;
refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject(null);
constructor(public authService: AuthService) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
console.log("httpRequest intercepted", req)
if (req.url.indexOf('refresh') !== -1 || req.url.indexOf('login') !== -1) {
return next.handle(req);
}
const jwtToken = this.authService.getJwtToken();
if (jwtToken) {
return next.handle(this.addToken(req, jwtToken)).pipe(catchError(error => {
if (error instanceof HttpErrorResponse
&& error.status === 403) {
return this.handleAuthErrors(req, next);
} else {
return throwError(error);
}
}));
}
return next.handle(req);
}
private handleAuthErrors(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (!this.isTokenRefreshing) {
this.isTokenRefreshing = true;
this.refreshTokenSubject.next(null);
return this.authService.refreshToken().pipe(
switchMap((refreshTokenResponse: LoginResponse) => {
this.isTokenRefreshing = false;
this.refreshTokenSubject
.next(refreshTokenResponse.authenticationToken);
return next.handle(this.addToken(req,
refreshTokenResponse.authenticationToken));
})
)
} else {
return this.refreshTokenSubject.pipe(
filter(result => result !== null),
take(1),
switchMap((res) => {
return next.handle(this.addToken(req,
this.authService.getJwtToken()))
})
);
}
}
addToken(req: HttpRequest<any>, jwtToken: any) {
return req.clone({
headers: req.headers.set('Authorization',
'Bearer ' + jwtToken)
});
}
}

Header.component.ts

import { Component, OnInit } from '@angular/core';
import {AuthService} from '../auth/shared/auth.service';
import {Router} from '@angular/router';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
isLoggedIn: boolean;
username: string;
constructor(private authService : AuthService, private router : Router){ }
ngOnInit(): void {
this.authService.loggedIn.subscribe((data: boolean) => this.isLoggedIn = data);
this.authService.username.subscribe((data: string) => this.username = data);
this.isLoggedIn = this.authService.isLoggedIn();
this.username = this.authService.getUserName();
console.log('header', this.isLoggedIn);
}
logout() {
this.authService.logout();
this.isLoggedIn = false;
this.router.navigateByUrl('');
}
}

auth.service.ts

import {EventEmitter, Injectable, Output} from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { SignupRequestPayload } from '../sign-up/signup-request.payload';
import {Observable, throwError} from 'rxjs';
import { LocalStorageService } from 'ngx-webstorage';
import { LoginRequestPayload } from '../login/login-request.payload';
import { LoginResponse } from '../login/login-response.payload';
import { map, tap } from 'rxjs/operators';
import {environment} from '../../../environments/environment';
@Injectable({
providedIn: 'root'
})
export class AuthService {
@Output() loggedIn: EventEmitter<boolean> = new EventEmitter();
@Output() username: EventEmitter<string> = new EventEmitter();
refreshTokenPayload = {
refreshToken: this.getRefreshToken(),
username: this.getUserName()
}
baseUrl = environment.baseUrl;
constructor(private httpClient: HttpClient,
private localStorage: LocalStorageService) {
}
signup(signupRequestPayload: SignupRequestPayload): Observable<any> {
return this.httpClient.post(this.baseUrl + 'api/auth/signup', signupRequestPayload, { responseType: 'text' });
}
login(loginRequestPayload: LoginRequestPayload): Observable<boolean> {
return this.httpClient.post<LoginResponse>(this.baseUrl + 'api/auth/login',
loginRequestPayload).pipe(map(data => {
this.localStorage.store('authenticationToken', data.authenticationToken);
this.localStorage.store('username', data.username);
this.localStorage.store('refreshToken', data.refreshToken);
this.localStorage.store('expiresAt', data.expiresAt);
this.loggedIn.emit(true);
this.username.emit(data.username);
return true;
}));
}
refreshToken() {
return this.httpClient.post<LoginResponse>(this.baseUrl + 'api/auth/refresh/token',
this.refreshTokenPayload)
.pipe(tap(response => {
this.localStorage.clear('authenticationToken');
this.localStorage.clear('expiresAt');
this.localStorage.store('authenticationToken', response.authenticationToken);
this.localStorage.store('expiresAt', response.expiresAt);
}));
}
logout() {
this.httpClient.post(this.baseUrl + 'api/auth/logout', this.refreshTokenPayload,
{ responseType: 'text' })
.subscribe(data => {
console.log(data);
}, error => {
throwError(error);
})
this.localStorage.clear('authenticationToken');
this.localStorage.clear('username');
this.localStorage.clear('refreshToken');
this.localStorage.clear('expiresAt');
}
getJwtToken() {
console.log('triggered)')
return this.localStorage.retrieve('authenticationToken');
}
getRefreshToken() {
return this.localStorage.retrieve('refreshToken');
}
getUserName() {
return this.localStorage.retrieve('username');
}
isLoggedIn(): boolean {
return this.getJwtToken() != null;
}
}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HeaderComponent } from './header/header.component';
import {HTTP_INTERCEPTORS, HttpClientModule} from '@angular/common/http';
import { MapComponent } from './map/map.component';
import { HomeComponent } from './home/home.component';
import {LoginComponent} from "./auth/login/login.component";
import {ReactiveFormsModule} from "@angular/forms";
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
import { ToastrModule } from 'ngx-toastr';
import {NgxWebstorageModule} from "ngx-webstorage";
import { CreateVehicleComponent } from './create-vehicle/create-vehicle.component';
import {TokenInterceptor} from './token-interceptor';
import { SignupComponent } from './auth/sign-up/sign-up.component';
import {NgbModule} from '@ng-bootstrap/ng-bootstrap';
@NgModule({
declarations: [
AppComponent,
HeaderComponent,
SignupComponent,
MapComponent,
HomeComponent,
LoginComponent,
CreateVehicleComponent
],
imports: [
BrowserModule,
AppRoutingModule,
ReactiveFormsModule,
HttpClientModule,
NgxWebstorageModule.forRoot(),
BrowserAnimationsModule,
ToastrModule.forRoot(),
NgbModule
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: TokenInterceptor,
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule { }

角版本

Angular CLI: 11.2.0
Node: 14.15.0
OS: win32 x64
Angular:
...
Ivy Workspace:
Package                      Version
------------------------------------------------------
@angular-devkit/architect    0.1102.0 (cli-only)
@angular-devkit/core         11.2.0 (cli-only)
@angular-devkit/schematics   11.2.0 (cli-only)
@schematics/angular          11.2.0 (cli-only)
@schematics/update           0.1102.0 (cli-only)

我的应用程序是基于Sai Upadhyayula在本教程中的工作:https://programmingtechie.com/2020/05/14/building-a-reddit-clone-with-spring-boot-and-angular/

如果你需要更多的细节请告诉我

您是否在产品中测试了您的构建本机模式?可能有环境文件问题。

尝试在本地运行Heroku,这将有助于轻松调试/找到根本原因

https://devcenter.heroku.com/articles/heroku-local

最新更新