我正在 NestJS 中编写 API,其中有一组通用标头。我决定使用拦截器将标头附加到传出请求中。标头不会附加到请求中,因此请求不断失败。
拦截器
import * as utils from '../utils/utils';
import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor
} from '@nestjs/common';
import { HEADERS } from '../middlewares/headers.constant';
import { Observable } from 'rxjs';
import { Request } from 'express';
import { DATA_PARTITION_ID } from '../app.constants';
@Injectable()
export class HeadersInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<void> {
const ctx = context.switchToHttp();
const request: Request = ctx.getRequest();
this.setHeaders(request);
return next.handle();
}
private setHeaders(request): void {
this.updateHeaders(request, HEADERS.ACCEPT, 'application/json');
this.updateHeaders(request, HEADERS.CONTENT_TYPE, 'application/json');
this.updateHeaders(request, HEADERS.ACCEPT_ENCODING, 'gzip, deflate, br');
this.updateHeaders(
request,
HEADERS.DATA_PARTITION_ID,
DATA_PARTITION_ID
);
this.updateHeaders(
request,
HEADERS.AUTHORIZATION,
`Bearer ${utils.parseCookies(request).stoken}`
);
this.updateHeaders(request, HEADERS.APP_KEY, '');
}
private updateHeaders(
request: Request,
property: string,
value: string
): void {
if (!request.headers.hasOwnProperty(property)) {
request.headers[property] = value;
} else {
void 0;
}
}
}
该拦截器只做一件事:访问请求并附加标头并将控制权传递给下一个处理程序。
Enums
export enum HEADERS {
DATA_PARTITION_ID = 'Data-Partition-Id',
AUTHORIZATION = 'Authorization',
CONTENT_TYPE = 'Content-Type',
APP_KEY = 'appkey',
ACCEPT = 'accept',
ACCEPT_ENCODING = 'accept-encoding'
}
控制器
import { Body, Controller, Post, Req, UseInterceptors } from '@nestjs/common';
import { HeadersInterceptor } from '../interceptors/headers.interceptor';
import { SearchData } from './models/search-data.model';
import { SearchResults } from './models/search-results.model';
import { SearchService } from './search.service';
@Controller('')
@UseInterceptors(new HeadersInterceptor())
export class SearchController {
constructor(private searchService: SearchService) {}
@Post('api/search')
async searchDataById(@Body() searchData: SearchData, @Req() req): Promise<SearchResults> {
console.log(req.headers);
return await this.searchService.getSearchResultsById(searchData);
}
}
Service
import { HttpService, HttpStatus, Injectable } from '@nestjs/common';
import { AppConfigService } from '../app-config/app-config.service';
import { DataMappingPayload } from './models/data-mapping-payload.model';
import { SearchData } from './models/search-data.model';
import { SearchModelMapper } from './search.service.modelmapper';
import { SearchResults } from './models/search-results.model';
import { ServiceException } from '../exception/service.exception';
@Injectable()
export class SearchService {
constructor(
private searchModelMapper: SearchModelMapper,
private configService: AppConfigService,
private readonly httpService: HttpService
) {}
async getSearchResultsById(searchData: SearchData): Promise<SearchResults> {
if (searchData.filters.collectionId) {
console.log(this.configService.appConfig.urls.SEARCH_RESULTS_BY_COLLECTION_ID_URL.replace(
'${collectionId}',
searchData.filters.collectionId
)
);
const searchResultsAPI = await this.httpService
.get(
this.configService.appConfig.urls.SEARCH_RESULTS_BY_COLLECTION_ID_URL.replace(
'${collectionId}',
searchData.filters.collectionId
)
)
.toPromise();
const kinds = this.searchModelMapper.getUniqueKinds(
searchResultsAPI.data.results
);
const mappingPayload = await this.getDataMapping(kinds);
return this.searchModelMapper.generateSearchResults(
kinds,
mappingPayload,
searchResultsAPI.data.results
);
} else {
this.raiseException();
}
}
async getDataMapping(kinds: string[]): Promise<[]> {
const entityKindNames: DataMappingPayload = {
entityKindNames: kinds
};
const dataMappingAPI = await this.httpService
.post(
this.configService.appConfig.urls.DATA_CATALOG_SERVICE_URL,
JSON.stringify(entityKindNames)
)
.toPromise();
return dataMappingAPI.data.entityViewData;
}
// To be moved to util functions
private raiseException(): void {
throw new ServiceException(
{
message: 'This does not have a collection id',
missing: 'Collection Id',
code: HttpStatus.BAD_REQUEST
},
HttpStatus.BAD_REQUEST
);
}
}
当我访问时req.headers
in the 控制器,我确实获得了需要通过拦截器设置的所有标头。
{
[0] 'accept-encoding': 'gzip, deflate, br',
[0] 'accept-language': 'en-US,en;q=0.9',
[0] cookie: '',
[0] 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36',
[0] 'content-type': 'application/json',
[0] accept: 'application/json',
[0] appkey: '',
[0] 'cache-control': 'no-cache',
[0] 'postman-token': 'cb397012-71aa-460a-b66b-28600538faf9',
[0] host: 'localhost:8080',
[0] 'content-length': '77',
[0] connection: 'keep-alive',
[0] 'Data-Partition-Id': 'tenant1',
[0] Authorization: 'Bearer TOKEN_HERE'
[0] }
当我检查实际请求的日志时,它说授权 is null
。这意味着请求不会被拦截,也不会附加标头。
有人遇到过类似的问题吗?