서버가 갖고 있는 여러 종류의 파일을 클라이언트에 그대로 전달해야 될 때가 있다.
서버에 저장된 이미지를 제공하는 이미지 서버라던가, json 데이터를 클라이언트에서 다운로드 받을 수 있도록 제공하는 등, 어떤 타입의 파일이라도 전달이 가능한데, express의 내장 미들웨어인 express.static()
메소드를 통해 이를 간단하게 구현할 수 있다.
npm init -y
npm i express
static
이라는 디렉토리를 만들어 npm init -y
로 모듈을 초기화 한 뒤, npm i express
로 express를 설치하자.
그리고 static 디렉토리 안에 public이라는 디렉토리를 생성해준다.
클라이언트에 제공할 파일들을 public 폴더 안에 모아두는 것이 일반적인 컨벤션이기 때문이다.
그리고 코드를 작성할 main.js 파일도 하나 만들어준다.
이제 디렉토리의 구조는 다음과 같을 것이다.
static 폴더 아래 public 폴더와 main.js, package.json 파일이 위치하고 있다.
// main.js
const express = require('express');
const app = express();
app.listen(3000, () => {
console.log('server is running at 3000');
});
항상 하던대로 기계적으로 express 서버의 기본 뼈대를 위와 같이 작성한다.
그리고 클라이언트에게 보내주기 위한 데이터 파일을 public 폴더 아래 people.json이라는 이름으로 만들어준다.
// people.json
[
{
"name": "John Doe",
"age": 43,
"gender": "Male",
"occupation": "Wokrer"
},
{
"name": "Mira Jaeger",
"age": 18,
"gender": "Female",
"occupation": "Student"
},
{
"name": "Margaret C. Terjo",
"age": 32,
"gender": "Female",
"occupation": "Teacher"
},
{
"name": "Margaret C. Terjo",
"age": 32,
"gender": "Female",
"occupation": "Teacher"
},
{
"name": "Matthew J. South",
"age": 45,
"gender": "Male",
"occupation": "Lawyer"
},
{
"name": "Ramon H. Reed",
"age": 35,
"gender": "Male",
"occupation": "Dentist"
}
]
클라이언트에서 해당 파일에 접근하여 데이터를 볼 수 있게 만들 것이다.
그러기 위해서는 몇가지 추가적인 작업이 필요한데, 간단하므로 쉽게 이해할 수 있을 것이다.
그 전에, 서버를 실행하고 GET /public/people.json
으로 접속해보자.
Cannot GET /public/people.json이라는 오류 메세지가 나타난다.
Network 탭을 확인해보면 404 Not Found로 응답을 받은 것을 볼 수 있다.
서버에 위치한 모든 파일을 클라이언트에서 멋대로 조회할 수 있다면 원하지 않는 중요한 파일도 모두 노출되어 보안에 문제가 생길 수 있기 때문에 클라이언트에 공개할 파일을 특정 폴더에 모은 뒤, 그 폴더를 공개하는 작업이 반드시 필요한 것이다.
const express = require('express');
const app = express();
const path = require('path');
const publicPath = path.join(__dirname, 'public');
app.use(express.static(publicPath));
app.listen(3000, () => {
console.log('server is running at 3000');
});
위 코드가 바로 그 작업을 하는 코드다.
앞서 봤듯, path.join()
은 플랫폼 별로 path의 구분자가 달라서 생기는 오류를 해결해주는 기능이고, __dirname
은 코드를 실행한 디렉토리의 path를 담고 있는 변수다.
/workspaces/node_workspace/static/main.js
를 실행했기 때문에 __dirname
은 /workspaces/node_workspace/static
이 되고, 'public'
을 인자로 주었기 때문에 publicPath
는 /workspaces/node_workspace/static/public
이 될 것이다.
해당 path를 express.static()
미들웨어에 인자로 주고 app.use()
로 미들웨어를 등록하면 /workspaces/node_workspace/static/public
에 위치한 모든 파일을 클라이언트에서 조회할 수 있게 된다.
다시 한 번 GET /public/people.json
으로 요청을 보내자.
여전히 404 Not Found가 뜨는 것을 볼 수 있다.
이유인 즉슨, main.js
가 위치한 경로를 루트, /
로 봤을 때는 /public/people.json
이라는 경로가 맞지만, express.static
에 public
를 등록한 순간, 자동으로 public
디렉토리 내부에 접근하여 파일을 찾기 때문에 GET /public/people.json
으로 접근하는 것은 GET /public/public/people.json
에 접근하는 것과 동일한 결과를 얻게 된다.
우리가 찾는 json 파일은 /public/public/people.json
이 아닌, /public/people.json
이기 때문에 다음 경로로 접근하는 것이 옳다.
GET /people.json
이제 데이터를 정상적으로 얻어올 수 있게 되었다.
이렇게 미리 만들어진 파일은 JS 코드 등에 의해 요청을 보낼 때마다 동적으로 생성/변경 되는 것이 아니라, 파일의 원형 그대로 전송되기 때문에 static serving(정적 제공)이라는 용어로 불린다.
그래서 미들웨어 이름도 express.static()
인 것이다.
React, Vue 등을 사용해봤다면, JS 코드를 실행하여 html을 동적으로 렌더링하는 것이 아닌, 미리 만들어진 html 파일 자체를 정적으로 제공하는 것과 같다고 생각해도 될 것 같다.
추가로 json 이외에 html, 이미지 파일 등도 public 폴더 안에 넣기만 한다면 그대로 클라이언트에서 접근이 가능하다.
<!-- /public/test.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test</title>
</head>
<body>
Test Page
</body>
</html>
test.html을 만들어서 public 폴더 안에 넣고 GET /test.html
으로 접속해보자.
잘 작동하는 것을 볼 수 있다.
마지막으로 nodejs.png
라는 위 이미지를 public 폴더 안에 넣고 GET /nodejs.png
로 접속해보자.
다른 이미지를 아무거나 다운로드 받아서 넣어도 무방하다.
역시 잘 작동한다.
static serving에 대해서 알아보았다.