프레임워크/Express

[2차 정리]node.js로 서버 제작시 필요한 상식

빨대도둑 2023. 9. 7. 01:04

모듈 시스템

프로그램 내부를 기능별 단위로 분할한 부분. 또는 메모리 보드 등의 부품을 간단하게 떼서 교환이 쉽도록 설계되어 있을 때의 그 각 구성원

모듈은 부품 같은 역할을 하므로 여러 부품을 조립해서 하나의 프로그램을 만듭니다.

어떤 프로그램을 만들지 몰라도 웹 서비스에서 필요한 공통 기능이 있습니다.

 

회원가입, 게시판 같은 기능이고, 이 기능을 미리 모듈로 만들어 놓으면 여러 홈페이지를 만들 때도 사용할 수 있습니다.

이렇게 기능 단위로 분리하고 기능을 이루는 코드를 모아서 캡슐화해 놓은 것을 ‘모듈’이라고 합니다.

모듈은 애플리케이션을 구성하고 애플리케이션을 이루는 기본 단위가 됩니다.

 

모듈을 사용하는 모듈 시스템을 도입하면 미리 만들어진 모듈을 이리저리 조립해서 내가 원하는 다양한 형태의 웹을 구현할 수 있고 그렇게 되면 구현 시간이 훨씬 단축됩니다.

모듈은 사실 하나의 자바스크립트 파일이라고 생각하면 됩니다.

 

하나 또는 여러 개의 기능별로 .js 파일을 만들어 필요한 곳에 require 해서 사용할 수 있습니다.

모듈 시스템은 객체 지향 프로그래밍에서 캡슐화(Encapsulation)와 동일한 개념입니다.

모듈로 API를 묶어줘서 변수나 함수에 name space를 보장해주고, 기능별로 코딩이 가능하고 모듈로 묶어 놓은 코드의 재사용이 가능해집니다.

*캡슐화: 객체의 속성(data fields)와 행위(메서드, methods)를 하나로 묶고 실제 구현 내용 일부를 외부에 감추어 은닉합니다.

*name space: 개체를 구분할 수 있는 범위를 말합니다.

 


 

Node.js는 모듈 시스템을 사용하며 우리는 ‘모듈’을 사용해 코드를 작성하게 됩니다.

일반적으로 자바스크립트는 브라우저 엔진에서 복수의 자바스크립트 파일을 로드해도 하나의 파일로 합쳐져서 동일한 유효범위를 갖습니다.

하지만 Node.js는 CommonJS를 따르고 있기 때문에 ‘모듈’을 사용해서 서로 다른 파일의 리소스(변수, 함수, 객체 등)을 주거니 받거니 해야 합니다.

*CommonJS: 자바스크립트를 브라우저뿐만 아니라 서버 측 애플리케이션이나 데스크톱 애플리케이션에서도 사용하고 조직한 자발적 워킹 그룹

 


 

모듈 시스템을 사용하는 중요한 이유중 하나는’ 전역변수’ 때문입니다.

Node.js에서 하나의 모듈은 자신만의 스코프(범위)를 가지기 때문에 전역 변수 중복 문제가 발생하지 않습니다.

A.js에서 선언한 변수 A와 B.js파일에서 선언한 변수 A는 서로 다른 변수가 됩니다.

 

따라서 자신의 스코프에서만 사용할 수 있었던 모듈의 기능을 다른 모듈에서 사용하려면 module.expeorts 또는 exports 객체를 통해 정의하고 외부에서 사용하고 싶다고 선언해야 합니다.

그리고 다른 모듈의 기능을 불러올 때는 require 를 통해 불러올 수 있습니다.

 

또한 A.js 모듈과 B.js 모듈이 서로 내부 요소를 참조하는 것도 가능한데 이를 ‘순환참조’라고 합니다.

자바스크립트 모듈 시스템에서는 순환참조를 허용합니다.

하지만 순환참조를 할 때 require()의 순서에 따라 오류가 발생할 수 있습니다.

실제로 순환 참조를 많이 사용하면 발생하는 여러 문제가 있습니다.

그러나 실행할 때 오류가 발생하는 것이 아니므로 순환 참조에 관해 오류가 발생하더라도 알아차리기 쉽지 않습니다.

 

모듈을 내보내는 방식

  • module.exports=프로퍼티;
    • 하나의 값(원시타입, 함수, 객체)를 할당 할 수 있음
    • module.exports 객체에 할당된 값 자체를 require()를 통해서 전달받음
  • exports.프로퍼티;
    • 값 자체를 할당하는 것이 아닌, 외부로 보낼 요소를 exports 객체의 프로퍼티 또는 멧드로 추가함
    • 프로프티와 메서드가 담긴 exports 객체를 require()로 받게됨.

 

모듈의 종류

Node.js는 기본적으로 제공하는 모듈의 수도 많고 npm을 통해서 설치할 수 있는 확장 모듈도 많습니다.

기본 모듈은 따로 require을 하지 않아도 사용할 수 있고, npm을 통해 설치할 수 있는 서드파티 모듈, 즉 확장 모듈은 터미널에서 ‘npm install 모듈명’ 명령어를 통해 설치하여 require 하여 사용할 수 있습니다.

  • 기본(코어) 모듈, 확장 모듈: 기본적으로 포함되어 있다면 기본(코어)모듈이고, 아니라면 확장 모듈입니다.
  • 일반모듈, 네이티브 모듈: 자바스크립트로 작성되었다면 일반 모듈이고 그 외의 언어로 작성되어 있다면 네이티브 모듈입니다.
  • 지역모듈, 전역 모듈: 현재 웹을 사용하기 위해서만 만들어졌으면 지역모듈이고, 어디든 사용할 수 있게 확장했다면 전역모듈입니다.

 

전역 객체(global)객체

전역 객체는 어디에서나 사용할 수 있는 개체를 의미합니다.

클라이언트(사용자)가 사용하는 자바스크립트, 즉 프론트 측의 자바스크립트에서는 window, document가 전역 객체가 됩니다.

하지만 서버 측의 자바스크립트에서는 global이라는 전역 객체를 사용합니다.

 


 

http 모듈로 서버 제작

const http = require('http');

http.createServer((req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
    res.write('<h1>Node.js로 서버만들기</h1>');
    res.end('<p>3장 http모듈 공부중입니다.</p>')
})
    .listen(8080, () => {
        console.log('8080포트에서 서버 연결 중 ..');
    });

createServer( ) 함수는 서버를 만드는 함수 입니다. 이 함수 안에 인자로 콜백 함수를 넣고, 콜백함수에는 요청에 대한 응답, 즉 어떤 이벤트를 받았을 때 실행해야 하는 작업을 작성합니다.

이 콜백 함수의 파라미터에는 두 가지 객체를 넣는데, 하나는 요청에 관한 정보를 담는 request를 줄여서 req라고 표기하고,

다른 하나는 응답에 관한 정보를 담고 response를 줄여 res라고 표기합니다.

 

createServer( )함수 뒤에 listen( )를 붙여 클라이언트와 연결할 포트번호와 서버가 연결되면 실행할 콜백 함수를 넣습니다.

res.writeHead( )는 응답에 대한 정보(헤더)를 기록하는 함수입니다.

파라미터로 요청코드와 콘텐츠의 타입을 넣어 줍니다.

res.write( )에는 파라미터로 클라이언트에 보낼 데이터를 넣어 줍니다.

res.end( )는 응답을 종료하는 메스드이며, 여기에 넣은 파라미터까지 전달하고, 응답을 종료하겠다는 의미입니다.

 


 

포트 번호 정보

Well-known ports: 0~1023번까지이며 이미 사용되고 있는 포트이기 때문에 따로 사용할 수 없습니다. Registered ports: 1024~49151번까지이며 벤더가 할당받아 사용하는 포트 입니다. Dynamic posts: 49152~65535 번까지이며 주로 시스템에서 사용합니다.

서버를 위해서는 주로 80 또는 8080 포트를 사용합니다.

 


 

const http = require('http');

const server = http.createServer((req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
    res.write('<h1>Node.js로 서버만들기</h1>');
    res.end('<p>3장 http모듈 공부중입니다.</p>')
})
    .listen(8080);

liseten( ) 메서드에 콜백을 넣는 대신 listening 이벤트 리스너를 붙여 사용할 수도 있고, 오류를 핸들링해주는 이벤트 리스너를 붙여 줄 수 도 있습니다.

또한 오류를 처리할 때 주의할 점은 오류가 발생해도 꼭 응답 콜백 함수를 작성해 주어야 한다는 점 입니다.

만약 오류가 발생한 수 실행할 응답이 없다면 서버는 응답이 오길 계속 기다리게 되고 결국에는 timeout 오류를 발생합니다.

 


 

요청객체(req), 응답 객체(res)

express를 사용해서 서버를 만들 때 가장 기본이 되는 것은 req객체와 res 객체, 그리고 객체의 여러 메서드를 사용하는 것 입니다.

const http = require('http');

http.createServer((req, res) => {
    if (req.url === '/') {
        res.write('Hello');
        res.end()
    }
})
    .listen(8080, () => {
        console.log('8080포트에서 서버 연결')
    });

req.url이 ‘/’라는 뜻은 localhost:8080 뒤의 주소가 / 라는 뜻 입니다.

즉 기본페이지 라는 뜻이 됩니다. 여러 url을 설정해주고 req.url이 기본 페이지일 때 기본 index.html을 띄우고,

req.url 이 회원가입 페이지일 때 signUp.html을 띄우는 형식으로 req.url을 이용하여 여러 페이지를 생성할 수 있습니다.

이처럼 요청을 보낼 때, 주소를 통해 내용을 표시하는 것을 REST라고 합니다.

 


 

틈새 상식: http, https, http2

https 모듈은 웹 서버에 SSL 암호를 추가해서 메서드로 데이터를 주고 받을 때 이를 암호화 할 수 있습니다.

따라서 실제로 웹 서버를 구현하고 실제 서비스에 이용하려면 http 모듈 대신 https 모듈을 이용해야 합니다.

https에 암호화를 적용하기 위해서는 인증기관에서 인증서를 발급 받아야하며 합니다.

http2는 https가 필수적으로 사용되야 하며 SSL암호화와 더불어 추가적으로 http 프로토콜인 http/2를 사용합니다.

 


 

express 모듈로 서버 만들기

Express란

https와 fs 모듈을 사용해서 서버를 일일이 구현할 수도 있지만, 서버의 규모가 커진다면 공통적으로 반복되는 코드가 많아 집니다.

express는 이를 해결해 줄 수 있는 프레임워크 입니다.

request와 responseㄹ르 완전히 통제할 수 있고, 가볍고, 빠르고 무료라는 장점까지 더해져 인기가 많은 프레임워크 입니다.

 

하지만 Node.js의 서브 파티 모듈입니다. 그래서 npm을 통해서 설치할 수 있습니다.

Node.js의 http와 connect 컴포넌트를 기반으로 동작하는데, connect 컴포넌트를 ‘미들웨어’라고도 합니다.

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

app.get('/', (req, res) => {
    res.send('Hello World!');
});

app.listen(8080, () =>
    console.log('8080포트에서 서버 실행중'));

가장 기본적인 express의 사용법 입니다.

http 모듈의 res 객체의 메서드 write( )대신, express의 res 객체의 send( ) 메서드를 통해 웹에 문자열 데이터를 전달합니다.

send( )함수 하나로 응답을 보내고, 종료하는 기능까지 합니다.

http모듈을 사용했던 것 보다 훨씬 짧은 코드로 서버를 생성할 수 있고 기존 http 모듈을 상속받았기 때문에 http 모듈의 기능을 모두 사용할 수 있습니다.

그렇지만 express 전용 객체를 사용하는 것이 좋습니다.

 


 

const express = require('express');

const app = express();
app.set('port', process.env.PORT || 8080);

app.get('/', (req, res) => {
    res.sendFile(__dirname + '/index.html');
});

app.listen(app.get('port'), () => {
    console.log(app.get('port'), '번 포트에서 서버 실행 중 ..')
});

html 파일을 보낼 때 fs 모듈에서의 readFile( )대신 sendFile( )을 사용할 수 있습니다.

http 모듈을 사용해서 응답을 보내줄 때 writeHeader를 통해 Content-Type과 Charset 정보까지 보내줘야 했지만,

express의 res 객체의 sendFile메서드를 사용하면 자동으로 자질구레한 정보를 클라이언트에 전송합니다.

 

또한 요청 주소를 여러 개 더 추가할 때 http 모듈에서는 if else를 사용해서 요청 주소를 분리해줘야 했지만,

express를 사용하면 app.get 등의 메서드로 깔끔하게 주소를 분리할 수 있는 등의 장점이 있습니다.

위의 코드는 가장 기본 틀이 되는 코드 입니다.

 

express를 require( )를 통해 불러오고 app 변수에 할당했습니다.

그런 다음 app.set(’port’, 포트번호)을 통해 서버가 실행될 포트를 지정합니다.

 

process.env.PORT는 process.env 객체에 기본 포트번호가 있다면 해당 포트를 사용한다는 뜻이고, 그렇지 않으면 8080포트를 사용하라고 지정합니다.

이처럼 app.set(키, 값)은 키, 값 파라미터를 이용하여 키에 값을 저장하도록 설정할 수 있는 함수입니다.

그리고 해당 데이터를 app.get(키) 함수를 통해 가져옵니다.

 

app.get(주소, 라우터)은 주소에 대한 GET 요청이 올 때 어떤 응답을 할지 적어줍니다.

마지막으로 app.listen( )을 통해 포트를 연결하고 서버를 실행합니다.

 


 

http요청 메서드: GET, POST, PUT, PATCH, DELETE

http 요청 메서드는 클라이언트(사용자)가 웹 서버에게 자신의 목적을 알리는 수단을 말합니다.

http 메서드 클라이언트에서 이런 저런 방식으로 요청이 들어와도 하나의 규격화된 방식으로 서버와 소통하며 응답을 보내줄 수 있기 때문입니다.

 

http 요청 메서드 종류와 내용

GET: 리소스를 얻을 때 사용

HEAD: 문서의 정보를 얻을 때 사용

POST: 리소스를 전달할 때 사용

PUT: 내용 전체를 갱신할 때 사용

PATCH: 내용을 부분적으로 갱신할 때 사용

DELETE: 파일을 삭제할 때 사용

 


 

미들웨어: middleware

중간 단계 역할을 하는 존재 입니다.

요청과 응답 사이에 express 자체에 있는 기능 외에 추가적인 기능을 넣어 줄 수 있습니다.

express 자체를 미들웨어로 사용해도 되고 다른 사람이 만들어 놓은 미들웨어를 npm을 통해 다운받아 사용해도 됩니다.

 

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

app.get('/', function (req, res, next) {
    res.send('Hello World!');
    next();
});

const myLogger = function (req, res, next) {
    console.log('LOGGED');
    next();
};

app.use(myLogger);

app.listen(8080);

미들웨어는 위에서 아래로 실행되기 때문서 순서가 중요합니다.

먼저 app.get(’/’)이 수행되고 res.send( )가 끝나고 응답을 종료해버리기 때문에 Logger까지 도달하지 않습니다.

next( )는 다음 미들웨어로 넘어가는 역할을 하기 때문에 순서를 잘 배치해 주고 next( )를 통해 흐름을 잘 제어해주어야 합니다.

 

next(error)는 오류처리 미들웨어로 가는 역할을 합니다.

next(’route’)는 next( )로 같은 라우터에서 분기 처리를 합니다.

 

오류 처리를 위한 미들웨어 함수는 총 네 개의 파라미터 erro, req, res, next를 가집니다.

오류는 오류처리 미들웨어에서 따로 다루어야 합니다.

 

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

app.use(function (err, req, res, next) {
    console.error(err.stack);
    res.status(500).send('Something broke!');
});

app.listen(3000);

보통은 express 서버를 만들 때 다음과 같은 과정을 거칩니다.

  1. express를 불러온다.
  2. 포트를 설정해준다.
  3. 공통적으로 사용하는 미들웨어를 장착한다.
  4. 라우터를 구성한다.
  5. 404 처리 미들웨어를 구성한다.
  6. 오류 처리 미들웨어를 구성한다.
  7. 생성된 서버가 포트를 리스팅한다.

 


 

자주 사용하는 미들웨어

express.static

정적 파일(static): 이미지, css, 스크립트 파일과 같이 그 내용이 고정되어 있어, 응답을 할 때 별도의 처리 없이 파일 내용을 그대로 보여주면 되는 파일입니다.

const express = require('express');

const app = express();
app.set('port', process.env.PORT || 8080);

app.use(express.static(__dirname + '/public'));

app.get('/', (req, res) => {
    res.sendFile(__dirname + '/index.html');
});

app.listen(app.get('port'), () => {
    console.log(app.get('port'), '번 포트에서 서버 실행 중 ..')
});

static은 express 안에 기본적으로 포함되어 있기 때문에 별도의 설치 없이 꺼내서 사용만 해주면 됩니다.

static( ) 안에 static 폴더로 지정해 줄 파일의 경로를 입력합니다.

 

그 뒤 static 폴더를 따로 지정해주면 지정한 파일이 바로 클라이언트로 가는 것이 아닌 ststic 미들웨어를 거친 후 도착하게 됩니다.

이렇게 지정했으면 static 파일들을 불러 html에 띄울 수 있습니다.

경로를 따로 명시해주지 않아도 자동으로 서버에서 static 폴더에서 해당 파일을 찾은 뒤 띄워주기 때문에 경로를 다 볼 수 없으니 보안에도 도움이 됩니다.

 


 

router

router도 일종의 미들웨어 입니다.

클라이언트로부터 요청(request)가 왔을 때 서버에서 어떤 응답(response)를 보내주어야 할지 결정해 줍니다.

HTTP 요청 메서드의 종류와 내용

GET/ : index.html 파일을 송신

GET/join : join.html 파일을 송신

POST/user : 사용자를 등록

PUT/user/user_id : user_id를 가진 사용자의 정보를 수정

DELETE/user/user_id : user_id를 가진 사용자의 정보를 삭제

const express = require('express');

const app = express();
app.set('port', process.env.PORT || 8080);

app.use(express.static(__dirname + '/public'));

app.get('/', (req, res) => {
    const output = `  
	        <h2>express로 웹 만들기</h2><br>  
	        <p>메인 페이지 입니다.</p><br>  
	        <img src="./sample.png" width="400px" height="200px"/>  
	    `
    res.send(output);
});

app.get('/user/:id', (req, res) => {
    res.send(req.params.id + "님의 개인 페이지 입니다.");
});

app.listen(app.get('port'), () => {
    console.log(app.get('port'), '번 포트에서 서버 실행 중 ..')
});

첫번째 파라미터로 넣어준 경로로 요청이 들어오면 두번째 파라미터의 미들웨어를 실행합니다.

첫번째 파라미터의 경로는 서버 자원을 가리키는 URL문자열인데, 회원가입의 경로이면 /join.html 처럼 만들어 줍니다

그리고 로그인 경로이면 /login.html 처럼 만들어 줍니다.

두번째 파라미터는 라우팅 로직 함수를 콜백 형태로 구현한 것이고 해당 주소의 요청을 받으면 미들웨어가 어떤 작업을 수행하게 됩니다.

 


 

응답을 위한 함수

res.send( ): 문자열로 응답

res.json( ): json 객체로 응담

res.render( ): Jade, pug와 같은 템플릿을 렌더링하여 응답

res.sendFile( ): 파일로 응답

 


 

morgan

morgan은 Logger API 입니다.

morgan은 request와 response를 깔끔하게 포매팅해주어 콘솔에 로그를 찍는 역할을 합니다.

그리고 찍힌 로그를 콘솔로만 확인해도 되지만, json형태로 dump 파일에 기록하게 해주는 winston이라는 모듈도 있습니다.

morgan에는 인자로 여러 옵션을 넣어줄 수 있고 옵션마다 보여주는 정보도 다릅니다.

주로 개발시에는 ‘dev’옵션을 사용하는데, 요청 메서드, url, 상태, 응답시간 등을 보여주고 배포시에는 ‘combined’옵션을 사용해 사용자의 주소, 브라우저 등 더 세부적인 정보를 로깅할 수 있습니다.

 


 

express.json, express.unlencoded

클라이언트에서 post, put 요청 시 들어온 정보를 가진 req.body에 접근하기 위해 필요한 미들웨어 입니다.

요청 정보가 url에 들어온 것이 아니라 request.body에 들어있는데 이 값을 읽을 수 있는 구문으로 파싱하고 req.body로 옮겨 주는 역할을 하는 것이 express.json, express.urlencoded입니다.

app.use(express.json());
app.use(express.urlencoded({extended:true}));

원래는 body-parser라는 미들웨어를 npm install을 통해 다운받아 장착해 주어야 했는데 이제 express 내장에 express.unlencoded라는 이름으로 사용할 수 있습니다.

express.json은 req.body가 json 형태일 때, express.urlencoded는 폼에 대한 요청일 때 사용합니다.

express.urlencoded의 extended옵션은 false로 설정하면 node.js에 내장된 queryString을 사용하고, true로 설정하면 npm의 qs 모듈을 사용합니다.

둘다 url 쿼리 스트링을 파싱해주지만 qs는 보안이 추가적으로 필요할 때 사용합니다.

또한 req.body가 이미지, 동영상 등의 multipart 형식의 데이터라면 multer 등 다른 다른 미들웨어를 추가적으로 설치해서 처리를 해주어야 합니다.

 


 

cookie-parser

클라이언트에게 요청을 받을 때, 사용자의 정보에 관해서는 IP 주소와 브라우저의 정보 정도만 알 수 있습니다.

따라서 그 정보만을 가지고 사용자를 식별하기는 힘들기 때문에 로그인을 구현하는 것이고, 그 로그인을 구현할 때 쿠키와 세션이 사용됩니다.

 

 

클라이언트가 요청을 보낼 때마다 키-쌍으로 이루어진 쿠키를 보내고 서버에서는 클라이언트가 보낸 쿠키를 읽어 사용자가 누군지 식별하게 됩니다.

보안이 필요한 건물에 들어갈 때 출입증이 있어야만 게이트를 통과할 수 있는 것처럼 쿠리는 출입증 같은 역할을 하는 존재입니다.

req.writeHead({'Set-Cookie': 'name=kingsman'});

처음에 한번만 서버에서 res.writeHead( ) 메서드를 통해 ‘Set-cookie’에 값을 넣어줍니다.

그러면 브라우저에 키-쌍으로 이루어진 쿠키가 헤더에 저장됩니다.

이렇게 한번 설정되고 난 후에는 브라우저에서 자동으로 쿠키를 매번 요청할 때마다 서버에게 보냅니다

const http = require('http');

http.createServer((req, res) => {
    res.writeHead(200, { 'Set-cookie': 'name=roadbook' });
    console.log(req.headers.cookie);
    res.end('Cookie --> Header');
})
    .listen(8080, () => {
        console.log('8080포트에서 서버 연결 중 ..');
    });

요청 헤더에도 들어가서 브라우저를 끄기 전까지 요청을 보낼 때마다 해당 쿠키 값도 같이 보내주게 됩니다.

브라우저를 끄기 전까지만 쿠키가 살아있는 이유는 쿠키의 expire를 지정해주지 않았기 때문에 기본 값으로 브라우저를 끄게 되면 쿠키 값이 없어집니다.

이렇게 쿠키 값을 통해 쿠키가 있을 때는 사용자 관련 화면을 , 없을 때는 로그인 화면을 보내주는 식으로 로그인을 구현할 수 있습니다.

 

클라이언트와 쿠키가 함께 요청을 보내면 req.headers.cookie를 통해 쿠키 값에 접근을 할 수 있게 됩니다.

req.headers.cookie에 저장된 값은 문자열인데, 이를 자바스크립트에서 사용하기 위해서는 객체로 파싱하는 과정이 필요합니다.

*파싱(parsing): 데이터를 원하는 형태로 가공하는 과정

 

Cookie-parser를 사용하면 따로 파싱한느 함수를 만들어 줄 필요 없이, express의 req 객체에 cookies 속성이 부여되므로 res.cookies.쿠키명을 통해 쿠키 값에 접근할 수 있게 됩니다.

쿠키만 사용하게 되면 개발자도구 탭의 Cookies 에서 쿠키 값을 확인할 수도 있고 값을 바꿀 수도 있게 됩니다.

따라서 실제 정보는 서버에만 저장해두고 브라우저에는 암호화된 키 값만 보내고 그 키 값으로 실제 값에 접근할 수 있도록 하는 것을 세션이라고 합니다.

 

const http = require('http');

const session = {};
const sessKey = new Date();
session[sessKey] = { name: 'python' };

http.createServer((req, res) => {
    res.writeHead(200, { 'Set-cookie': `session=${sessKey}` });
    res.end('Session-Cookie --> Header');
})
    .listen(8080, () => {
        console.log('8080포트에서 서버 연결 중 ..');
    });

세션 저장용 객체 하나를 session이라는 변수에 생성하고, 키 값을 sessKey라는 변수에 생성함.

express-session 미들웨어를 이용하면 임의의 키 값을 생성할 수 있음.

 

sessoin객체에 sessKey라는 키 값을 지정하고 값을 {name-’python’}으로 할당함

그리고 쿠키 값을 바로 보내주는 것이 아니라 세션 값으로 생성한 키 값을 넣어줌

그렇게 되면 쿠키 값이 바로 뜨는 것이 아니라 세션 값이 보여지게 됨.

 

해당 세션도 마찬가지로 express-session이 없다면 cookies.session 값을 이용해서 세션을 다루어야 하지만,

express-session을 이용한다면 res 객체에 session 속성이 부여되어 req.session을 통해 접근할 수 있게 됨.

 


 

미들웨어 통합 테스트

npm install morgan cookie-parser express-session
const express = require('express');
const morgan = require('morgan');
const cookieParser = require('cookie-parser');
const session = require('express-session');
const app = express();

/* 포트 설정 */
app.set('port', process.env.PORT || 8080);

/* 공통 미들웨어 */
app.use(express.static(__dirname + '/public'));
app.use(morgan('dev'));
app.use(cookieParser('secret@1234')); // 암호화된 쿠키를 사용하기 위한 임의의 문자 전송
app.use(session({
    secret: 'secret@1234', // 암호화
    resave: false, // 새로운 요청시 세션에 변동 사항이 없어도 다시 저장할지 설정
    saveUninitialized: true, // 세션에 저장할 내용이 없어도 저장할지 설정
    cookie: { // 세션 쿠키 옵션 들 설정 httpOnly, expires, domain, path, secure, sameSite
        httpOnly: true, // 로그인 구현시 필수 적용, javascript로 접근 할 수 없게 하는 기능
    },
    // name: 'connect.sid' // 세션 쿠키의 Name지정 default가 connect.sid
}));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

/* 라우팅 설정 */
app.get('/', (req, res) => {
    if (req.session.name) {
        const output = `  
                <h2>로그인한 사용자님</h2><br>  
                <p>${req.session.name}님 안녕하세요.</p><br>  
            `
        res.send(output);
    } else {
        const output = `  
                <h2>로그인하지 않은 사용자입니다.</h2><br>  
                <p>로그인 해주세요.</p><br>  
            `
        res.send(output);
    }
});

app.get('/login', (req, res) => { // 실제 구현시 post
    console.log(req.session);
    // 쿠키를 사용할 경우 쿠키에 값 세팅 
    // res.cookie(name, value, options)
    // 세션 쿠키를 사용할 경우
    req.session.name = '로드북';
    res.end('Login Ok')
});

app.get('/logout', (req, res) => {
    res.clearCookie('connect.sid'); // 세션 쿠키 삭제
    res.end('Logout Ok');
});

/* 서버와 포트 연결.. */
app.listen(app.get('port'), () => {
    console.log(app.get('port'), '번 포트에서 서버 실행 중 ..')
});

express-session을 사용하지 않고 세션을 구현하면 따로 const session={ };과 같이 세션 정보를 저장할 공간을 따로 마련해 주어야 합니다.

하지만 express-session을 사용해서 req.session을 가지게 되면, req.session은 방금 요청을 보낸 사람의 고유한 저장 같은 곳으로 사용할 수 있게 됩니다.

‘/’ 페이지로 접속했을 때 req.session.name 값이 있으면, 즉 ‘/login’ 페이지로 먼저 접속해 req.session.name 값이 생성되어 있을 경우 ‘로그인한 사용자’라는 제목을 출력하고, req.session.name의 값이 없다면’ 로그인하지 않은 사용자’라는 제목을 출력합니다.

next( )가 없는 이유는 내부에 내장되어 있기 때문에 자동으로 다음 미들웨어로 넘어가기 때문입니다.

단 static의 경우 next( )가 없기 때문에 static을 거쳐야 하는 router라면 공통 미들웨어의 순서를 잘 설정해 주여야 합니다.