군붕이의 메모장

[Nest.js] euc-kr 인코딩 변환하기 본문

웹 개발/백엔드

[Nest.js] euc-kr 인코딩 변환하기

초보군붕이 2023. 6. 28. 22:31
반응형

● Nest.js의 body-parser

Nest.js의 경우 기본적으로 bodyparser 라이브러리를 사용해서 json 데이터를 변환한다.

 

nest new [name]을 통해서 nestjs 프로젝트를 생성하면 아래 사진처럼 node_modules 내부에 bodyparser가 설치되어있다.

 

bodyparser

 

자바스크립트는 기본적으로 UTF 인코딩을 지원하기때문에 실제 bodyparser 내부를 들여다보면 UTF를 제외한 인코딩 방식은 에러로 처리하는것을 확인할 수 있다.

 

body-parser/lib/types/json.js

// assert charset per RFC 7159 sec 8.1
var charset = getCharset(req) || 'utf-8'
if (charset.slice(0, 4) !== 'utf-') {
  debug('invalid charset')
  next(createError(415, 'unsupported charset "' + charset.toUpperCase() + '"', {
    charset: charset,
    type: 'charset.unsupported'
  }))
  return
}

 

실제로 Nest.js의 동작방식으론 HTTP 요청에 대해서 라우터에 도달하기전에 JSON 데이터를 파싱하게된다.

하지만 euc-kr등 다른 캐릭터셋으로 요청을 하게되면 body-parser에 의해서 아래처럼 에러가 발생한다.

 

UnsupportedMediaTypeError

 

 

● 에러가 안나도록 데이터 받기

간단하게 생각하면 간단하다.

데이터를 받을때 body-parser를 통해서 받지말고 그냥 직접 받으면 된다.

Nest.js는 8번대 버전과 9번대 이상 버전의 처리방식이 다르다.

 

 

● Nest.js 8.X 버전 해결방법

9점대 버전에는 rawBody 옵션을 통해서 편하게 처리가 가능하다.

하지만 8점대 버전에는 해당 옵션이 존재하지 않으므로 미들웨어를 통해서 직접 처리해줘야 한다.

 

1. body-parser 비활성화

body-parser가 기본적으로 활성화 되있어서 비활성화 하지 않으면 위 사진처럼 HTTP 415 에러가 발생한다.

// main.ts
async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    bodyParser: false
  });
  await app.listen(3000);
}
bootstrap();

 

2. 데이터 처리용 미들웨어 생성

API에 따라서 어떻게 JSON 데이터를 처리할지 정하기 위해서 미들웨어를 사용한다.

// raw-body.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response } from 'express';
import * as bodyParser from 'body-parser';

@Injectable()
export class RawBodyMiddleware implements NestMiddleware {
  public constructor() {}

  public use(req: Request, res: Response<any>, next: () => any): any {
    bodyParser.raw({ type: '*/*' })(req as any, res as any, next);
  }
}

content-type과 관계없이 body에 대해서 전부 raw 형식으로 처리한다는 의미이다.

 

// json-body.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response } from 'express';
import * as bodyParser from 'body-parser';

@Injectable()
export class JsonBodyMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: () => any) {
    bodyParser.json()(req as any, res as any, next);
  }
}

UTF-8 요청의 경우 body-parser의 일반 json 메소드를 통해서 처리한다.

 

3. 미들웨어 등록

// app.module.ts
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { RawBodyMiddleware } from './middlewares/raw-body.middleware';
import { JsonBodyMiddleware } from './middlewares/json-body.middleware';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(RawBodyMiddleware).forRoutes('create/euc-kr');
    consumer.apply(JsonBodyMiddleware).forRoutes('create/utf-8');
  }
}

각 API의 URI에 따라서 특정 미들웨어를 적용시켜준다.

 

 

4. 컨트롤러 설정

import { Controller, Post, Body } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Post('create/euc-kr')
  createEuckr(@Body() raw: Buffer) {
    console.log('EUC-KR 데이터 : ', raw.toString());
  }

  @Post('create/utf-8')
  createUtf8(@Body() body: any) {
    console.log('UTF-8 데이터 : ', body);
  }
}

@Body()를 사용해서 데이터를 받게되면 Buffer <aa bb cc...> 형식의 데이터를 받게된다.

해당 버퍼 데이터를 toString()을 통해서 변환해주면 정상적으로 euc-kr 데이터를 받을 수 있다.

 

console.log 결과

 

 

● Nest.js 9.X 이상 버전 해결방법

우선 8점대 버전과 다른점은 rawBody를 사용할 수 있다는 점이다.

8점대 버전처럼 굳이 미들웨어를 생성하지 않아도되서 매우 편리하다

 

상세 내용은 공식문서를 참고하면 좋다.

https://docs.nestjs.com/faq/raw-body

 

Documentation | NestJS - A progressive Node.js framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Rea

docs.nestjs.com

 

1. rawBody 활성화

// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    rawBody: true
  });
  await app.listen(3000);
}
bootstrap();

rawBody를 활성화하면 body를 raw 형식으로 받을 수 있다.

 

 

2. 컨트롤러 설정

// app.controller.ts
import { Controller, Post, Body, RawBodyRequest, Req } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Post('create/euc-kr')
  createEuckr(@Req() req: RawBodyRequest<Request>) {
    const raw = req.rawBody;
    console.log('EUC-KR 데이터 : ', raw.toString());
  }

  @Post('create/utf-8')
  createUtf8(@Body() body: any) {
    console.log('UTF-8 데이터 : ', body);
  }
}

8점대 버전과 다른점은 req 객체 내부에 rawBody라는 데이터가 들어온다는 점이다.

RawBodyRequest<Request>를 req 타입에 할당해야 타입에러 없이 접근이 가능하다.

 

console.log 결과

 

 

● 코드

https://github.com/imkdw/nestjs-euckr

 

GitHub - imkdw/nestjs-euckr: nestjs에서 euc-kr 인코딩 변환하기

nestjs에서 euc-kr 인코딩 변환하기. Contribute to imkdw/nestjs-euckr development by creating an account on GitHub.

github.com

 

반응형