当拦截器在服务发出值之前运行时,如何在传出请求上设置默认值 headers
How to set default headers on outgoing requests, when the interceptor runs before a value is emitted from a service
我在将令牌从 auth.service.ts
中的 POST 响应传递到 HttpInterceptor 并在授权 header 中设置令牌时遇到问题。
据我了解,在任何 HTTP 请求、拦截、修改和 return 克隆版本之前,拦截器 运行s。
但是我的 header 没有更新。在 auth.service 具有 运行 并且 BehaviorSubject 的新值已发出之前,拦截器只是 returns tokenSubject$
的默认值 null
。
浏览器控制台
interceptor null
auth.service.ts:19 {token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}
auth.service.ts:21 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
原始 headers
Host: localhost:3000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:70.0) Gecko/20100101 Firefox/70.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost:4200/login
Authorization: Bearer null
Content-Type: application/json
Content-Length: 52
Origin: http://localhost:4200
DNT: 1
Connection: keep-alive
我应该如何向授权添加令牌 header?
auth.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AuthService {
tokenSubject$ = new BehaviorSubject(null);
constructor(private httpClient: HttpClient) {}
login(userEmailAndPassword: { email: string, password: string }) {
return this.httpClient
.post<{ token: string }>('http://localhost:3000/users/login', userEmailAndPassword)
.subscribe(user => {
console.log(user); // { token: "eyJhbGciOiJIUzI..." }
this.tokenSubject$.next(user.token);
console.log(this.tokenSubject$.value); // "eyJhbGciOiJIUzI..."
});
}
}
jwt-interceptor.ts
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Injectable } from '@angular/core';
import { AuthService } from './auth.service';
@Injectable()
export class JwtInterceptor implements HttpInterceptor {
constructor(private authService: AuthService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const setAuthorizationToken = req.clone({
headers: req.headers.set('Authorization', `Bearer ${this.authService.tokenSubject$.value}`)
});
console.log('interceptor', this.authService.tokenSubject$.value);
return next.handle(setAuthorizationToken);
}
}
app.module.ts
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { LoginComponent } from './login/login.component';
import { JwtInterceptor } from './jwt-interceptor';
import { RouterModule, Routes } from '@angular/router';
import { UsersComponent } from './users/users.component';
const routes: Routes = [
{path: 'login', component: LoginComponent},
{path: 'signup', component: SignupComponent},
{path: 'users', component: UsersComponent}
];
@NgModule({
declarations: [
AppComponent,
SignupComponent,
LoginComponent,
UsersComponent
],
imports: [
RouterModule.forRoot(routes),
BrowserModule,
HttpClientModule,
ReactiveFormsModule
],
providers: [{provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true}],
bootstrap: [AppComponent]
})
export class AppModule {}
HTTP 请求
POST http://localhost:3000/users/login
Content-Type: application/json
{
"email": "mr@mr.com",
"password": "myawesomepassword"
}
HTTP 响应
POST http://localhost:3000/users/login
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Content-Length: 209
ETag: W/"d1-MJNo/MXLpxhkX1PE78vlqkKR5GQ"
Date: Wed, 28 Aug 2019 09:07:42 GMT
Connection: keep-alive
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Response code: 200 (OK); Time: 15ms; Content length: 209 bytes
您应该将授权令牌保存在服务以外的其他地方,因为每次重新加载页面时它都将为空。我建议使用 localstorage:
login(userEmailAndPassword: { email: string, password: string }) {
return this.httpClient
.post<{ token: string }>('http://localhost:3000/users/login', userEmailAndPassword)
.subscribe(user => {
console.log(user); // { token: "eyJhbGciOiJIUzI..." }
this.tokenSubject$.next(user.token);
localStorage.setItem('token', user.token);// --> Here u are saving the token to localstorage
console.log(this.tokenSubject$.value); // "eyJhbGciOiJIUzI..."
});
}
你也可以保存整个用户对象:
login(userEmailAndPassword: { email: string, password: string }) {
return this.httpClient
.post<{ token: string }>('http://localhost:3000/users/login', userEmailAndPassword)
.subscribe(user => {
console.log(user); // { token: "eyJhbGciOiJIUzI..." }
this.tokenSubject$.next(user.token);
localStorage.setItem('user', JSON.stringify(user));// --> Here u are saving the user to localstorage
console.log(this.tokenSubject$.value); // "eyJhbGciOiJIUzI..."
});
}
要从本地存储中检索用户,您必须将其解析为 JSON:
JSON.parse(localStorage.getItem("user"));
然后在你的拦截器中这样做:
const setAuthorizationToken = request.clone({
headers: new HttpHeaders({
'Content-Type': 'application/json',
Authorization: 'Bearer ' + localStorage.getItem('token') === null ? '' : localStorage.getItem('token');
})
});
通常我会编写一个 UserService 来从本地存储中检索 token/user。
此致
我在将令牌从 auth.service.ts
中的 POST 响应传递到 HttpInterceptor 并在授权 header 中设置令牌时遇到问题。
据我了解,在任何 HTTP 请求、拦截、修改和 return 克隆版本之前,拦截器 运行s。
但是我的 header 没有更新。在 auth.service 具有 运行 并且 BehaviorSubject 的新值已发出之前,拦截器只是 returns tokenSubject$
的默认值 null
。
浏览器控制台
interceptor null
auth.service.ts:19 {token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}
auth.service.ts:21 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
原始 headers
Host: localhost:3000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:70.0) Gecko/20100101 Firefox/70.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost:4200/login
Authorization: Bearer null
Content-Type: application/json
Content-Length: 52
Origin: http://localhost:4200
DNT: 1
Connection: keep-alive
我应该如何向授权添加令牌 header?
auth.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AuthService {
tokenSubject$ = new BehaviorSubject(null);
constructor(private httpClient: HttpClient) {}
login(userEmailAndPassword: { email: string, password: string }) {
return this.httpClient
.post<{ token: string }>('http://localhost:3000/users/login', userEmailAndPassword)
.subscribe(user => {
console.log(user); // { token: "eyJhbGciOiJIUzI..." }
this.tokenSubject$.next(user.token);
console.log(this.tokenSubject$.value); // "eyJhbGciOiJIUzI..."
});
}
}
jwt-interceptor.ts
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Injectable } from '@angular/core';
import { AuthService } from './auth.service';
@Injectable()
export class JwtInterceptor implements HttpInterceptor {
constructor(private authService: AuthService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const setAuthorizationToken = req.clone({
headers: req.headers.set('Authorization', `Bearer ${this.authService.tokenSubject$.value}`)
});
console.log('interceptor', this.authService.tokenSubject$.value);
return next.handle(setAuthorizationToken);
}
}
app.module.ts
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { LoginComponent } from './login/login.component';
import { JwtInterceptor } from './jwt-interceptor';
import { RouterModule, Routes } from '@angular/router';
import { UsersComponent } from './users/users.component';
const routes: Routes = [
{path: 'login', component: LoginComponent},
{path: 'signup', component: SignupComponent},
{path: 'users', component: UsersComponent}
];
@NgModule({
declarations: [
AppComponent,
SignupComponent,
LoginComponent,
UsersComponent
],
imports: [
RouterModule.forRoot(routes),
BrowserModule,
HttpClientModule,
ReactiveFormsModule
],
providers: [{provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true}],
bootstrap: [AppComponent]
})
export class AppModule {}
HTTP 请求
POST http://localhost:3000/users/login
Content-Type: application/json
{
"email": "mr@mr.com",
"password": "myawesomepassword"
}
HTTP 响应
POST http://localhost:3000/users/login
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Content-Length: 209
ETag: W/"d1-MJNo/MXLpxhkX1PE78vlqkKR5GQ"
Date: Wed, 28 Aug 2019 09:07:42 GMT
Connection: keep-alive
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Response code: 200 (OK); Time: 15ms; Content length: 209 bytes
您应该将授权令牌保存在服务以外的其他地方,因为每次重新加载页面时它都将为空。我建议使用 localstorage:
login(userEmailAndPassword: { email: string, password: string }) {
return this.httpClient
.post<{ token: string }>('http://localhost:3000/users/login', userEmailAndPassword)
.subscribe(user => {
console.log(user); // { token: "eyJhbGciOiJIUzI..." }
this.tokenSubject$.next(user.token);
localStorage.setItem('token', user.token);// --> Here u are saving the token to localstorage
console.log(this.tokenSubject$.value); // "eyJhbGciOiJIUzI..."
});
}
你也可以保存整个用户对象:
login(userEmailAndPassword: { email: string, password: string }) {
return this.httpClient
.post<{ token: string }>('http://localhost:3000/users/login', userEmailAndPassword)
.subscribe(user => {
console.log(user); // { token: "eyJhbGciOiJIUzI..." }
this.tokenSubject$.next(user.token);
localStorage.setItem('user', JSON.stringify(user));// --> Here u are saving the user to localstorage
console.log(this.tokenSubject$.value); // "eyJhbGciOiJIUzI..."
});
}
要从本地存储中检索用户,您必须将其解析为 JSON:
JSON.parse(localStorage.getItem("user"));
然后在你的拦截器中这样做:
const setAuthorizationToken = request.clone({
headers: new HttpHeaders({
'Content-Type': 'application/json',
Authorization: 'Bearer ' + localStorage.getItem('token') === null ? '' : localStorage.getItem('token');
})
});
通常我会编写一个 UserService 来从本地存储中检索 token/user。
此致