Nest JS Interceptors: невозможно установить заголовки HTTP для исходящих запросов. - PullRequest
1 голос
/ 23 марта 2020

Я пишу API в Nest JS, у которых есть набор общих заголовков. Я решил использовать перехватчики для добавления заголовков к исходящим запросам. Заголовки не добавляются к запросу, и, следовательно, запрос продолжает сбой.

Перехватчик

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

Этот перехватчик выполняет одну вещь: доступ к запросу и добавьте заголовки и передайте управление следующему обработчику.

Перечисления

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 в контроллере , я получаю все заголовки, которые мне нужно было установить через перехватчики .

{
[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] }

Когда я проверяю журналы фактического запроса, он говорит: Авторизация равна null . Это означает, что запрос не перехватывается и не добавляется в заголовки.

Кто-нибудь сталкивался с подобной проблемой?

Ответы [ 3 ]

0 голосов
/ 23 марта 2020

Если заголовки всегда нужны для внешних HTTP-вызовов, вы можете добавить Axios Interceptor непосредственно в гнездо Js HttpService так же, как он делает в этой записи , чтобы зарегистрировать его запрос.

Важная часть:

  1. Создайте app.module.ts орудие OnModuleInit
  2. Добавьте метод onModuleInit()
  3. В onModuleInit(), добавьте this.httpService.axiosRef.interceptors.request.use(functionThatWillAddHeadersToRequest(config));

config содержит всю информацию, необходимую для запроса, включая заголовки.

Теперь все ваши исходящие запросы, использующие HttpService, должны иметь ваш HTTP заголовки.

Ax ios перехватчики github

0 голосов
/ 13 апреля 2020

Я просто хочу поделиться своим опытом, как добавить базу пользовательских заголовков для текущего запроса

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],
    }),
})

Я использовал настраиваемый поставщик и вводил запрос, чтобы я мог определить, какие заголовки я буду установить базу на основе данного запроса, это было бы полезно, поскольку мы могли бы динамически устанавливать любые заголовки на основе запроса, не задавая его вручную для каждого запроса ios.

и использовать его на основе Nest JS Документация

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

    findAll(): Observable<AxiosResponse<Cat[]>> {
        return this.httpService.get('http://localhost:3000/cats');
    }
}
0 голосов
/ 23 марта 2020

Если я правильно вас понимаю, вы хотите добавить заголовки к исходящему HTTP-вызову с HttpService. interceptor в гнезде JS работает на IncomingMessage (входящие запросы в целом) и ServerResponse (или исходящих ответах в целом). Он не видит вещи, отправленные с HttpService или любого другого HTTP-клиента. Вместо этого вам нужно установить заголовки на уровне метода или на уровне модуля, если они являются общими значениями. У HttpModule есть метод register и registerAsync, который можно использовать для передачи значений каждому вызову HttpService, поэтому, если у вас есть общие заголовки, вы можете управлять ими следующим образом:

@Module({
  imports: [
    HttpModule.register({
      headers: {} // object of headers you want to set
    }),
  ]
})
export class MyModule {}

И теперь, когда вы используете httpService.get(url), вы отправите заголовки вместе с ним.

...