NestJS拦截器:无法在传出请求上设置HTTP标头 [英] NestJS Interceptors: Unable to set HTTP Headers on outgoing requests

查看:703
本文介绍了NestJS拦截器:无法在传出请求上设置HTTP标头的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在NestJS中编写具有一组通用标头的API.我决定使用拦截器,以便将标头附加到传出的请求中.标头不会附加到请求中,因此请求继续失败.

I am writing APIs in NestJS which have a set of common headers. I decided to use interceptors in order to append headers to outgoing requests. The headers do not get appended to the request and hence the request keep on failing.

拦截器

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;
    }
  }
}

此拦截器仅做一件事,访问请求并附加标头,然后将控件传递给下一个处理程序.

This interceptor does simply one thing, access the request and append the headers and pass the control to next handler.

枚举

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);
  }
}

服务

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 时,我确实通过拦截器获得了需要设置的所有标题.

When I access req.headers in the controller, I do get all the headers that I needed to set via interceptors.

{
[0]   'accept-encoding': 'gzip, deflate, br',
[0]   'accept-language': 'en-US,en;q=0.9',
[0]   cookie: '_ga=GA1.2.1433024000.1564057108; wfx_unq=AL2gejqqEGELJ5FQ; trafficManagerV2Token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik1UVTJOakU0T0RJNE1nP
T0ifQ.eyJwZXJtaXRVcmwiOiJodHRwczovL2V2ZC5kYXRhLmRlbGZpLmNsb3VkLnNsYi1kcy5jb20vIiwiY291bnRyeUNvZGUiOiJJTiIsImlzcyI6ImNmcy10cmFmZmljLW1hbmFnZXIiLCJpYXQiOjE1NjYyNzM3ND
gsImV4cCI6MTU2NjI4ODE0OCwiYXVkIjoiaHR0cHM6Ly9ldmQuZGF0YS5kZWxmaS5jbG91ZC5zbGItZHMuY29tLyJ9.QHvZGR4DXdGpsWWNCnypPFttaBlpBCBSvy2N_Z0mgSD6W86g4f61GhO2XzFyIm7P20qAjkXHl
3CIo8R66wtYQqMIAOEd2BPcJVnKg9vdt2kxd1Fhk66BWTFd_xtTdyEgcwMuCmEkYEeFK1_cXrlbeGYpaRiXD6w6K1_2U1Wxtbu82BNp7R4eAuiLRbbLBdsuPgLwXsOI8YpFTMdpiUDMnZnTfw-Fr2F93KMzHKTswLy0y
QZVPtONj8BwXDPf15s2vLiTyzgof4ByM7O_eBIbBDse5tFufBXFABnr709Oi6AKUGMeVKsgwCo1d1Yxs7MR6nbNmyG3rFxKzhk5Xxehzw; x-origin-country=IN; stoken=eyJ0eXAiOiJKV1QiLCJhbGciOiJSU
zI1NiIsImtpZCI6Ik1UVTRORGcxTWpFeU1BPT0ifQ.eyJzdWIiOiJycHJhYmh1N0BzbGIuY29tIiwiaXNzIjoic2F1dGgtcHJldmlldy5zbGIuY29tIiwiYXVkIjoidGVzdC1zbGJkZXYtZGV2cG9ydGFsLnNsYmFwcC
5jb20iLCJpYXQiOjE1ODQ5Mzk3MjYsImV4cCI6MTU4NTAyNjEyNiwicHJvdmlkZXIiOiJzbGIuY29tIiwiY2xpZW50IjoidGVzdC1zbGJkZXYtZGV2cG9ydGFsLnNsYmFwcC5jb20iLCJ1c2VyaWQiOiJycHJhYmh1N0
BzbGIuY29tIiwiZW1haWwiOiJycHJhYmh1N0BzbGIuY29tIiwiYXV0aHoiOiIiLCJsYXN0bmFtZSI6IlByYWJodSIsImZpcnN0bmFtZSI6IlJ1c2hpa2VzaCBTdWJoYXNoIiwiY291bnRyeSI6IiIsImNvbXBhbnkiOi
IiLCJqb2J0aXRsZSI6IiIsInN1YmlkIjoiRjBfSUMxSjl4SHBaSGVUbnVBaWRCYVhtdzI1YmxuOUhYSXIwMnNscW8wTSIsImlkcCI6Im8zNjUiLCJoZCI6InNsYi5jb20iLCJkZXNpZCI6InJwcmFiaHU3LXNsYi1jb2
0tNWZkODc5NzZAZGVzaWQuZGVsZmkuc2xiLmNvbSIsImNvbnRhY3RfZW1haWwiOiJycHJhYmh1N0BzbGIuY29tIiwicnRfaGFzaCI6IlAzUG1yRXd5WExCR1VwTi05TTdybEEifQ.Z61iRRoS7J1IpF_V_rWLcrgeaSf
QyZG3K5vU4jps_LqB3VkPSvjHXLdv7Ga_LLPI_v2J-WFityHVBnYxLEzKmOuNc_jToPwmBqCmLLfSzIFGiJrFKby09ZbVoCCLHxjyUwB_Uc2VmWuYLce7oPpVFxelgRqnRjO3ymlPm65OvrR09fHiOlo52TULwbyyzeg
xzfodkl0eVTM7TURDi1RxGNHvw8Ghxt--AVIcgCT7hBDxA6w11D7Cr6fWBp1VpE2yawTESUWtZJn5tBmMZeZq2QobptNcuFdiAstQpvi_B5MqY1HY5LjVLOb2jAnEoCTl_gmEfyWr_aIKAFioK4YcQQ; _gid=GA1.2.
1341318697.1566283218; account-id=tenant1; _gat=1; traffic-manager-token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik1UVTRORGcxTWpFeU1BPT0ifQ.eyJwZXJtaXRVcmwi
OiJodHRwOi8vbG9jYWxob3N0OjgwODAiLCJjb3VudHJ5Q29kZSI6IklOIiwiaXNzIjoiY2ZzLXRyYWZmaWMtbWFuYWdlciIsImlhdCI6MTU4NDkzMTk5NywiZXhwIjoxNTg0OTQ2Mzk3LCJhdWQiOiJodHRwOi8vbG9j
YWxob3N0OjgwODAifQ.uVs2Uuy_Okzn0t3GPESH7cCR4OAb_ISr160JrydaKfkHogaKsuNEa7BI1vgQY8uywYle2P_sRaYT_FaoR9cF2iqHH7R7YHVdKEdNm_Gb2ji8nnLMjXORAMB78YtHt4SvnCNYrAxTqRPVhxRot
dQc6dcrVgzkxKxedDvnZTR81DfoOa00oeKrU7X62MSGMRDmz7TYLNxbaw0viJ-MlJ2AMHs_YhyRSHvmmG_5d0TVfNLBSnAiXlTH06iigVXfT5v-BbRukJJzaW1Pj30fde2G2ni0SZ8sK6nlrpu_0Tlu5-v1dKmdofhBs
qC8y8sCjZ8fTw4yZICl5AwPGZ4IOLkAeg',
[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 eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik1UVTRORGcxTWpFeU1BPT0ifQ.eyJzdWIiOiJycHJhYmh1N0BzbGIuY29tIiwiaXNzIjoic2F1dGgtcHJldmlldy5z
bGIuY29tIiwiYXVkIjoidGVzdC1zbGJkZXYtZGV2cG9ydGFsLnNsYmFwcC5jb20iLCJpYXQiOjE1ODQ5Mzk3MjYsImV4cCI6MTU4NTAyNjEyNiwicHJvdmlkZXIiOiJzbGIuY29tIiwiY2xpZW50IjoidGVzdC1zbGJk
ZXYtZGV2cG9ydGFsLnNsYmFwcC5jb20iLCJ1c2VyaWQiOiJycHJhYmh1N0BzbGIuY29tIiwiZW1haWwiOiJycHJhYmh1N0BzbGIuY29tIiwiYXV0aHoiOiIiLCJsYXN0bmFtZSI6IlByYWJodSIsImZpcnN0bmFtZSI6
IlJ1c2hpa2VzaCBTdWJoYXNoIiwiY291bnRyeSI6IiIsImNvbXBhbnkiOiIiLCJqb2J0aXRsZSI6IiIsInN1YmlkIjoiRjBfSUMxSjl4SHBaSGVUbnVBaWRCYVhtdzI1YmxuOUhYSXIwMnNscW8wTSIsImlkcCI6Im8z
NjUiLCJoZCI6InNsYi5jb20iLCJkZXNpZCI6InJwcmFiaHU3LXNsYi1jb20tNWZkODc5NzZAZGVzaWQuZGVsZmkuc2xiLmNvbSIsImNvbnRhY3RfZW1haWwiOiJycHJhYmh1N0BzbGIuY29tIiwicnRfaGFzaCI6IlAz
UG1yRXd5WExCR1VwTi05TTdybEEifQ.Z61iRRoS7J1IpF_V_rWLcrgeaSfQyZG3K5vU4jps_LqB3VkPSvjHXLdv7Ga_LLPI_v2J-WFityHVBnYxLEzKmOuNc_jToPwmBqCmLLfSzIFGiJrFKby09ZbVoCCLHxjyUwB_U
c2VmWuYLce7oPpVFxelgRqnRjO3ymlPm65OvrR09fHiOlo52TULwbyyzegxzfodkl0eVTM7TURDi1RxGNHvw8Ghxt--AVIcgCT7hBDxA6w11D7Cr6fWBp1VpE2yawTESUWtZJn5tBmMZeZq2QobptNcuFdiAstQpvi_B
5MqY1HY5LjVLOb2jAnEoCTl_gmEfyWr_aIKAFioK4YcQQ'
[0] }

当我查看实际请求的日志时,它说授权.这意味着请求不会被拦截,也不会附加标头.

When I check the logs of the actual request, it says Authorization is null. Which means the request is not intercepted and not being appended with headers.

有人遇到过类似的问题吗?

Has anyone faced similar issue?

推荐答案

我只想在这里分享我的经验,如何根据正在进行的请求添加自定义标头

I just want to share my experience here how to add custom header base on an ongoing request

import { REQUEST } from '@nestjs/core';
import { Module, HttpModule } from '@nestjs/common';

@Module({
    HttpModule.registerAsync({
        useFactory: request => {
            let automated = 0;
            if (request.get('host').includes('localhost')) {
                automated = 1;
            }
            return { headers: { automated } };
        },
        inject: [REQUEST],
    }),
})

我使用了自定义提供程序并注入了请求,因此我可以根据给定的请求确定要设置的标头,这将很有帮助,因为我们可以根据给定的请求动态设置任何标头,而无需手动设置每个axios请求.

I've used the custom provider and injecting the request so I could identify what headers I'll be setting base on the request given, this would be helpful since we could dynamically set any headers base on request given without manually setting it per axios request.

并基于 NestJS文档

@Injectable()
export class CatsService {
    constructor(private httpService: HttpService) {}

    findAll(): Observable<AxiosResponse<Cat[]>> {
        return this.httpService.get('http://localhost:3000/cats');
    }
}

这篇关于NestJS拦截器:无法在传出请求上设置HTTP标头的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆