nestjs перехватывает и изменяет исходящий http-запрос - PullRequest
0 голосов
/ 14 сентября 2018

Так что я, вероятно, что-то упускаю или делаю что-то не так. У меня есть приложение NestJS, которое пытается сделать http-запрос к внешнему API. Я хотел бы иметь возможность перехватить этот исходящий запрос и изменить заголовки перед его выполнением.

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

Ответы [ 3 ]

0 голосов
/ 20 сентября 2018

Давайте сначала разберемся с

Я пытался использовать перехватчики безрезультатно, входящие запросы HTTP перехватываются, но не исходящие.

Согласно документацииhttps://docs.nestjs.com/interceptors должно быть полностью возможно перехватить ответ.

@Injectable()
export class TransformHeadersInterceptor implements NestInterceptor {
  intercept(
    context: ExecutionContext,
    call$: Observable<any>,
  ): Observable<any> {
    // Get request headers, e.g.
    const userAgent = context.switchToHttp().getRequest().headers['user-agent'];

    // Not sure if headers are writeable like this, give it a try
    context.switchToHttp().getResponse().headers['x-api-key'] = 'pretty secure';

    return call$;
  }
}

Если вы хотите манипулировать заголовками на основе данных ответа.Вы можете использовать данные следующим образом:

return call$.pipe(map(data => {
    // Your code here
    return data;
}));

У меня есть некоторые мысли по поводу:

У меня есть приложение NestJS, которое пытается сделать http-запрос навнешний API.Я хотел бы иметь возможность перехватить этот исходящий запрос и изменить заголовки перед его выполнением.

Так что я думаю, что есть два варианта использования.Во-первых, у вас есть набор заголовков по умолчанию, которые изначально назначаются http-клиенту и отправляются с каждым запросом.Например:

import { HTTP_TOKEN } from './constants';
import * as http from 'request-promise-native';

export const httpProviders: any = [
  {
    provide: HTTP_TOKEN,
    useFactory: () => {
      return http.defaults({
        headers: {
          'Accept': 'application/json',
          'Content-type': 'application/json',
          'User-agent': 'my-?-app',
        },
      });
    },
  },
];

И, во-вторых, вы создаете и назначаете заголовки для каждого запроса.Это когда вы используете перехватчики.В контексте аутентификации вы можете подумать об использовании охраны, как предлагает Тано в своем ответе.

0 голосов
/ 07 ноября 2018

У меня была похожая проблема при изменении / добавлении заголовков ответов.Следующий код работал для меня:

@Injectable()
export class TransformHeadersInterceptor implements NestInterceptor {
  intercept(
    context: ExecutionContext,
    call$: Observable<any>,
  ): Observable<any> {

    return call$.pipe(
            map((data) => {
                // pipe call to add / modify header(s) after remote method
                let req = context.switchToHttp().getRequest();
                req.res.header('x-api-key', 'pretty secure');
                return data;
            }),
        );
  }
}
0 голосов
/ 14 сентября 2018

Я могу привести пример, в котором я использую внешние вызовы API:

import { PaginateModel, PaginateResult, Document } from 'mongoose';
import { AxiosInstance } from 'axios';
import { UseGuards, InternalServerErrorException, Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { Context } from './decorators/ctx.decorator';

@Injectable()
@UseGuards(AuthGuard('jwt'))
export abstract class ServiceBase<T extends Document> {
    protected abstract readonly path: string;

    constructor(protected readonly externals: Object, protected readonly model: PaginateModel<T>) {}

    async create(data: T, ctx: Context): Promise<T> {
        try {
            this.validate(data);
            const { lng, core } = this.separate(data);
            const catalog = new this.model(core);
            const head = await catalog.save();
            Object.assign(head, lng);
            const Authorization = ctx.token;
            const axios: AxiosInstance = this.externals[ctx.lang];
            try {
                const resp = await axios.post(`${this.path}`, head, { headers: { Authorization } });
                return resp.data;
            } catch (err) {
                // in case of any error the head record should be removed.
                catalog.remove();
                throw err;
            }
        } catch (err) {
            console.log(err);
            throw new InternalServerErrorException(err);
        }
    }

    abstract async validate(data: T): Promise<any>;

    abstract separate(data: T);

    async update(id: string, data: T, ctx: Context): Promise<T> {
        try {
            const curr = await this.model.findById(id).exec();
            const { lng, core } = this.separate(data);
            Object.assign(curr, core);
            await curr.save();
            Object.assign(core, lng);
            const Authorization = ctx.token;
            const axios: AxiosInstance = this.externals[ctx.lang];
            const resp = await axios.put(`${this.path}/${id}`, core, { headers: { Authorization } });
            return resp.data;
        } catch (err) {
            throw new InternalServerErrorException(err);
        }
    }

    async get(id: string, ctx: Context): Promise<T> {
        try {
            const Authorization = ctx.token;
            const axios: AxiosInstance = this.externals[ctx.lang];
            const resp = await axios.get(`${this.path}/${id}`, { headers: { Authorization } });
            return resp.data;
        } catch (err) {
            console.log(err);
            return null;
        }
    }

    async findOne(query: object): Promise<T> {
        const data = await this.model.findOne(query, { _class: 0 }).exec();
        return data;
    }

    async findAll(ctx: Context): Promise<T[]> {
        try {
            const Authorization = ctx.token;
            const axios: AxiosInstance = this.externals[ctx.lang];
            const resp = await axios.get(`${this.path}`, {
                headers: { Authorization },
            });
            return resp.data;
        } catch (err) {
            console.log(err);
            return null;
        }
    }

    async find(query: {} = {}, page: number, rows: number, ctx: Context): Promise<PaginateResult<T>> {
        try {
            const Authorization = ctx.token;
            const axios: AxiosInstance = this.externals[ctx.lang];
            const resp = await axios.get(`${this.path}`, {
                params: { page, rows },
                headers: { Authorization },
            });
            return resp.data;
        } catch (err) {
            console.log(err);
            return null;
        }
    }
}

, где внешние:: 1004 *

import axios, { AxiosInstance } from 'axios';

const config = require('../../config/settings.json');

export const externalProviders = {
    provide: 'ExternalToken',
    useFactory: () => {
        const externals = {};
        for (const lang in config.externals) {
            externals[lang] = axios.create({
                baseURL: config.externals[lang],
            });
        }
        return externals;
    }
};
...