웹 애플리케이션 구조 (Feat. CORS)

이선예·2023년 9월 26일
0

학습기록

목록 보기
1/1
post-thumbnail

서론

이번에 기획서를 바탕으로 처음부터 배포까지 하나의 웹 서비스를 개발해보았다.
처음에 많이 혼동스러웠던 부분이 웹 애플리케이션의 구조였다.
이전에 팀 프로젝트를 할 때는 프론트엔드와 백엔드 포지션이 나눠져 있어서, 자연스럽게 각자 맡은 포지션에서 프레임워크를 사용해서 개발을 했었다.
하지만 이번에는 혼자 개발을 해야했기 때문에 어디서부터 어디서까지가 프론트엔드고 백엔드일까? 고민거리가 생겼다. 초반에 이 고민에 대한 해답을 찾기위해 시간을 많이 썼지만, 이 후 프로젝트를 완성해나가면서 하나하나의 기능을 구현할 때마다 UI개발, API 개발 등 명확하게 구분해서 단계적으로 개발할 수 있어서 구조를 잡고 개발하길 잘했다는 생각이 들었다.


먼저 웹 애플리케이션의 일반적인 시스템 아키텍처인 Web Application Three Tier Architecture를 보자.

웹 애플리케이션의 3단계 계층 구조

  1. Client/Presentation Layer (웹 프론트 서버, 웹 서버)

    • 사용자 인터페이스(UI)를 처리하는 역할
    • 주로 웹 브라우저를 통해 클라이언트와 상호작용하고, 사용자의 웹 브라우저가 보낸 HTTP요청을 받아 HTTP응답을 반환하는 서버
    • API요청의 경우 Application Layer에 처리를 위임하며 결과를 최종 Client에 전달해준다.
    • 웹 서버의 기능은 Nginx, Apache와 같은 미들웨어로 구축할 수 있다.
  2. Server/Application Layer

    • 웹 애플리케이션의 비즈니스 로직을 처리하는 역할
      (즉, 앱을 통해 제공하고자 하는 서비스를 구현하기 위해 데이터를 직접적으로 처리하는 로직)
  3. Database/Data Access Layer

    • DB에 접근하여 데이터를 저장하거나 조회하는 역할
  4. Cross-Cutting

    • 보안, 통신, 운영 관리 등의 애플리케이션 전체에 걸쳐 사용되는 부가기능을 모듈화하여 재사용할 수 있도록 지원하는 역할
    • 부가기능적인 측면에서 보았을때 공통된 요소를 추출하여, 가로(횡단) 영역의 공통 부분을 잘라냈다고 하여 Cross-Cutting이라 부른다.
  1. Third-party integrations
    • 제 3의 API 서비스 이용하는 것을 의미
    • 소셜 로그인 API, PG사를 이용한 결제 API 등

2,3번을 실제 예시로 들어보면, 앱 서버에 Routes-Controller-Services 구조를 적용했을때, 다음과 같이 역할을 분리할 수 있다.

  1. Routes - Server/Application Layer
    엔드포인트에 따라 어떤 Controller가 수행되어야 하는지 정의, 사용자 입력의 유효성을 체크하는 부분을 Controller가 실행되기 전에 미들웨어로 추가할 수 있다.
  2. Controller - Server/Application Layer
    라우트로부터 요청을 받아 해당 요청에 대한 비즈니스 로직(Service)을 수행하고 클라이언트에게 응답 데이터를 반환하거나 에러를 처리한다.
  3. Service - Database/Data Access Layer
    비즈니스 로직을 구현하고 컨트롤러에게 해당 로직을 제공, 주로 데이터베이스와 상호작용한다.
    이때, Routes, Controller가 Application Layer에, Service가 Database Access Layer에 해당된다.

이렇게 웹 애플리케이션 구조를 나눴을 때, 동작 원리는 다음과 같다.

웹 서버는 HTML, CSS, JavaScript, 이미지와 같은 정적인 리소스를 전달하고, 웹 애플리케이션 서버는 요청에 따라 생성되거나 DB에서 추출 또는 변경이 될 수 있는 동적인 데이터를 웹 서버에 제공하여 웹 서버는 이를 클라이언트에게 전달한다. 클라이언트는 동적 데이터를 기반으로 웹 페이지를 렌더링하게 된다.


Q&A

WAS 하나로 정적, 동적인 데이터를 클라이언트에 제공할 수 있는데 굳이 서버를 두 개로 나눠야 하나요?

  1. WAS만으로 정적, 동적인 데이터를 처리할 수 있으나, 하나의 서버에 역할이 몰리면 동적 콘텐츠 처리가 지연될 수 있다.
    따라서, 서버 부하를 방지하기 위해 단순 정적 콘텐츠는 웹 서버가 제공하도록 역할을 분리하는 것이다.

  2. 클라이언트의 상호 작용에 따라 바로 서버에 요청하는 것이 아니라 웹 서버를 거쳐서 앱 서버에 전달하는 것이 포트 번호를 한 번 더 우회해 보안을 더 강화할 수 있다.

  3. 규모가 커질수록 개발 영역을 명확히하여 관리와 개발 효율을 높일 수 있고, 배포 및 유지보수가 편리하다.

    이 외에도 웹 서버의 중요한 역할인 리버스 프록시에 대해 알아보면 좋을 것 같다.

웹 서버와 앱 서버 분리 시 CORS(Cross-Origin Resource Sharing)이슈가 발생하지 않나요?

브라우저가 origin을 비교하는 기준은 다음과 같다.

출처(Origin)는 Protocol, Host, Port를 모두 합친 URL을 의미하고, 셋 중 하나라도 다르다면 Origin이 다르다고 판단한다.
https의 기본 포트는 4403이고, http의 기본포트는 80으로 포트를 명시하지 않아도 프로토콜에 따라 포트가 달라진다.
따라서 웹 서버와 앱 서버를 분리한다면 클라이언트의 요청을 받아 웹 서버에서 API요청을 하게 되는데, 이때 API의 주소가 달라지므로 cors 이슈가 발생한다.
이를 해결하는 방법은 Node.js 기반의 웹 애플리케이션을 개발한다고 가정했을때, 프론트엔드 입장에서와 백엔드 입장에서 제시하자면 다음과 같다.

  1. 프론트엔드에서 백엔드 서버에서 cors를 해결하는 코드가 없다면, proxy를 사용해 cors정책을 우회할 수 있다.
    http-proxy-middleware 라이브러리를 사용하거나 webpack dev server를 사용중이라면, webpack dev server에서 proxy기능을 제공하고 있기 때문에 webpack config에서 다음과 같이 설정할 수 있다.
    module.exports = {
       devServer: {
        proxy: { //api요청 프록시 설정
          '/api/': {
            // /api/로 시작하는 url은 아래의 전체 도메인을 추가하고, 옵션을 적용
            target: 'http://localhost:5000', // 클라이언트에서 api로 보내는 요청은 주소를 5000포트로 바꿔서 보내겠다 라는 뜻
            changeOrigin: true, // cross origin 허용 설정
          },
        },
      },
    };
    nginx로 배포하는 경우, nginx conf 다음과 같이 설정할 수 있다.
    server {
      location /api {
        proxy_pass http://localhost:5000; // /api 경로로 오는 요청을 이 url로 전달
      }
    }
  2. 백엔드에서 cors 해결하는 방법으로는, express를 사용한다고 가정했을 때 Access-Control-Allow-Origin 헤더 세팅을 하거나 cors 미들웨어를 사용해 해결할 수 있다.
    직접 헤더를 설정하는 경우는 다음과 같이 응답에 헤더를 추가할 수 있다.
    app.get('/api', (req, res) => {
      res.header('Access-Control-Allow-Origin', '허용하고자 하는 도메인');
      res.send(data)
    });
    cors 미들웨어를 사용하는 경우 먼저 cors 라이브러리를 설치하고, 아래와 같이 설정할 수 있다.
    app.use(cors({
      origins: '허용하고자 하는 도메인',
    }))

이는 CORS 정책을 준수하여 서로 다른 origin 간의 리소스를 공유할 수 있게 하는 것이고, XSS나 CSRF와 같은 공격에 대한 대비는 따로 해줘야 한다.


[Web] 웹 애플리케이션 아키텍처 개념 정리 및 구현, 기술
웹 서버 구조
CORS 개념 & 해결법

profile
의미있는 훈련 기록 저장소

0개의 댓글