백엔드/Node.js

[Node.js/express] express의 기본

MINJIN's 2024. 1. 2. 09:23

1. express란?

  express는 경량화 웹 개발 프레임 워크로, 노드를 이용한 웹 서비스나 웹 애플리케이션 개발에 가장 널리 쓰이는 확장 모듈 중 하나이다. express는 기본 모듈 중 하나인 http 모듈을 이용하여 웹 서버를 구축하고 데이터를 표시하는 방식을 좀 더 추상화하여 웹 서비스나 웹 애플리케이션 개발을 더 편리하고 수월하게 할 수 있도록 다양한 API를 제공한다.

  Node.js에서의 구현과 동일하게 이벤트 처리를 통합해 가는 기본적인 개발 스타일은 변함이 없지만, 준비되어 있는 다양한 객체를 통해 쉽게 필요한 처리를 만들 수 있다.

 

2. express 기반의 웹 서버 생성

1) package.json 파일 생성

  먼저 'package.json' 파일을 생성해야 하는데, 아래의 명령어를 터미널에 입력하면 된다. 'package.json' 파일은 웹 서버의 동작 설정 및 라이브러리 설치를 기록하기 위한 목적이다.

$ npm init

  위 명령어를 입력하면 파일 생성을 위한 정보들을 단계별로 입력해야 하는데 모든 항목에 반드시 기입할 필요는 없다. 필자는 아래와 같이 입력했다.

{
	"name": "board",
    "version": "1.0.0",
    "description": "",
    "main": "server.js",
    "dependencies": {
    	"express": "^4.18.2"
    },
    "devDependencies": {},
    ▷ Debug
    "scripts": {
    "test": "echo \"Error: no test speified\" && exit 1"
    },
    "author": "lch"
    "license": "ISC"
}

 

2) express 설치

아래 명령어를 입력하여 express를 설치한다.

$ npm install express

  express를 설치하면 왼쪽 탐색기에 'node_module'이라는 폴더가 생성되는데 폴더 내부를 살펴보면 알 수 없는 수많은 파일이 등록되어 있다. 이는 express를 설치하면서 관련 라이브러리 파일들을 모두 가져왔기 때문이다. 앞으로 추가로 설치하는 모든 라이브러리도 여기에 포함될 것이며, 이제 express를 사용하여 서버를 쉽게 만들 수 있다.

 

3) express를 사용한 서버 코드 작성

  'Server' 폴더를 선택하고 'server.js'라는 이름으로 새 파일을 추가한다. 이후 다음 코드를 작성한다.

const express = require('express')
const app = express();

app.listen(8080, function(){
	console.log("포트 8080으로 서버 대기중 ...");
});

 

1줄 : express 라이브러리를 require 하여 express 객체를 생성한다.
2줄 : express 객체를 사용하여 새로운 app 객체를 반환한다. app 객체가 서버 객체라고 생각하면 되고, app 객체로 서버의 기능을 하나씩 만들어가면 된다.
4줄 : listen 함수는 서버를 띄우고 클라이언트의 요청을 기다리는 함수다. 함수의 첫 번째 전달인자에는 서버에 띄울 포트번호, 두 번째 전달인자에는 서버를 띄운 후 실행할 코드를 작성한다.

function 함수는 서버 구동시 실행할 콜백 함수이다. 콜백함수는 이와 같이 이름이 없는 익명함수의 형태로 자주 사용된다. 

 

  코드 작성 후 터미널에 다음과 같은 명령어를 입력하여 서버를 구동시킨다.

$ node server.js

  터미널에서는 '포트 8080으로 서버 대기중 ...' 이 출력되고, 브라우저 주소창에 'localhost:8080'를 입력하여 접속하면 'Cannot Get / '이라는 메시지가 나타나는데, 이는 잘못된 것이 아니라 아직 요청에 대한 처리 루틴을 만들지 않았기 때문에 나타나는 문구이며 정상적으로 작동한다는 것이다. 

 

3. Routing

  클라이언트는 서버에 URI 및 특정한 HTTP 요청 메소드(GET, POST 등)로 요청을 전달한다. 이러한 클라이언트 요청에 응답하는 방법을 결정하는 것을 라우팅이라 한다. 각 라우트는 하나 이상의 핸들러 함수를 가질 수 있으며, 이러한 함수는 라우트가 일치할 때 실행된다. 라우트 정의에는 다음과 같은 구조가 필요하다.

1) GET 요청 처리 루틴

  일반적으로 포털 사이트 같은 곳에서 웹서핑을 할 때 대부분 GET 요청을 통해 수행된다. 원하는 메뉴를 클릭할 때마다 해당 항목에 대한 내용을 url로 GET 요청하고 서버로부터 원하는 페이지를 보여 준다. 'server.js'에 아래의 코드를 추가한다.

const express = require('express')
const app = express();

app.listen(8080, function(){
	console.log("포트 8080으로 서버 대기중 ...");
});

app.get('/book', function (req, res) {
    res.send('도서 목록 관련 페이지입니다.');
});
8줄 : get 함수는 요청 url 과 콜백 함수, 두 개의 인자를 전달한다. 콜백 함수 또한 2개의 전달인자가 있는데 req(request, 요쳥), res(response, 응답)가 있으며 req에는 웹 브라우저에서 요청시의 정보들이 모두 들어오며, res는 서버가 다시 웹 브라우저로 데이터를 전송할 때 사용하는 변수이다.
9줄 : res의 send 함수를 사용하여 요청한 웹 브라우저로 '도서 목록 관련 페이지입니다.'라는 메시지를 전송한다.

 

  코드 작성 이후 터미널에서 서버를 재가동한 후, 브라우저 주소창에 'http://localhost:8080/book' 입력하면 아래와 같은 형식으로 페이지가 나타나는 것을 확인할 수 있다.

2) 서버에서 HTML 파일 전송

① send 함수의 한계

  위와 같은 형식을 페이지에 나타내려면 다음과 같은 코드를 작성해야 한다.

// 윗줄 생략

app.get('/', function (req, res) {
    res.send(
        '<html>\
        <body>\
        <h1>홈입니다.</h1>\
        <marquee>반갑습니다.</marquee>\
        </body>\
        </html>'
    );
});

  send 함수 내 코드를 살펴보면 단지 두 문장을 출력한 것인데도 불구하고 가독성이 떨어지며, 내용을 추가하게 되면 코드는 훨씬 더 복잡해질 것이다. 그러므로 더 효율적인 방법인 sendFile 함수를 사용해야 한다.

 

② sendFile 함수

  기존 코드를 다음과 같이 수정한다.

// 윗줄 생략

app.get('/', function (req, res) {
    res.sendFile(__dirname + '/index.html');
});
4줄 : __dirname은 node 내부에 현재 디렉토리를 나타내는 문자열 변수로 선언되어 있다. 문자열끼리 + 기호로 합칠 수 있으므로 현재 디렉토리에 '/index.html' 문자열을 결합하여 요청 웹 브라우저로 보낸다.

 

  아직 'index.html' 파일을 만들지 않았으므로 파일 생성 후 코드를 작성한다.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Home</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
</head>

<body>
    <nav class="navbar navbar-expand-lg bg-body-tertiary">
        <div class="container-fluid">
            <a class="navbar-brand" href="#">Navbar</a>
            <button class="navbar-toggler" type="button" data-bs-toggle="collapse"
                data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false"
                aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarSupportedContent">
                <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                    <li class="nav-item">
                        <a class="nav-link active" aria-current="page" href="#">Home</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">Link</a>
                    </li>
                    <li class="nav-item dropdown">
                        <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown"
                            aria-expanded="false">
                            Dropdown
                        </a>
                        <ul class="dropdown-menu">
                            <li><a class="dropdown-item" href="#">Action</a></li>
                            <li><a class="dropdown-item" href="#">Another action</a></li>
                            <li>
                                <hr class="dropdown-divider">
                            </li>
                            <li><a class="dropdown-item" href="#">Something else here</a></li>
                        </ul>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link disabled" aria-disabled="true">Disabled</a>
                    </li>
                </ul>
                <form class="d-flex" role="search">
                    <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
                    <button class="btn btn-outline-success" type="submit">Search</button>
                </form>
            </div>
        </div>
    </nav>
    <h1>홈입니다.</h1>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-HwwvtgBNo3bZJJLYd8oVXjrBZt8cqVSpeBNS5n7C8IVInixGAoxmnlMuBnhbgrkm"
        crossorigin="anonymous"></script>
</body>

</html>

  필자는 부트스트랩을 활용하여서 홈 UI페이지와 내비게이션 바를 상단에 추가하였다. 이후 서버를 재구동한 후, 브라우저 주소창에 'http://localhost:8080/' 입력하면 아래와 같은 형식으로 페이지가 나타나는 것을 확인할 수 있다.

 

 

 

 

 

 

 

 

 

- 참고문헌

https://poiemaweb.com/express-basics

https://inpa.tistory.com/entry/EXPRESS-%F0%9F%93%9A-%EC%9D%B5%EC%8A%A4%ED%94%84%EB%A0%88%EC%8A%A4-%EC%84%A4%EC%B9%98-%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EA%B8%B0