본문 바로가기

BackEnd/Express.js

Express Basic Essentials - Form,Cookie,Session(END)

Form Session Cookie

 

익스프레스에 관한 마지막 포스팅이 되겠다.

익스프레스에서 가장 중요한 영역이다.

3개를 나열해놓으니 문뜩 영화 놈놈놈(좋은놈,나쁜놈,이상한놈)이 생각난다.

각설하고.. Express 에서 폼을 다루는 방식에 대해서

살펴보고자 한다.

GET 방식과 POST 방식에 차이점에 대해서 생각해보자 너무나 기초적 이다 보니

구글링해보면 똑같은 내용에 글들이 수도없이 나올것이다.

몇가지 차이가 있지만 그중에서 내가 생각하기에 중요한 차이는

POST 방식에서만 파일 전송이 가능하다는 점이다.

Express 에서 폼을 다루는 방식에 대해서 살펴보면 POST는 조금 특별하다는것을 알수

있을것이다.

GET

req.query 를 통해 접근이 가능하며 별도의 설정이 필요없고

자바스크립트 배열의 특성중에 하나인 subscript notation 이 가능하다.

코드에서 first name 이라는 띄어쓰기가 있는 태그 name 속성이 있다.

req.query.frist name 으로 호출이 불가능하다.

이럴때 다음과 같이 호출하면 된다.

    //이러한 태그가 있다고 가정해보자.
    <input type="text" name="name" />
    <input type="text" name="first name" />
    //get 라우팅에서..
    router.get('/hello',function(req, res) {
        var name = req.query.name;
        var firstName = req.query['first name']; // subscript notation
        });

기존에 get 방식에서 쿼리문자열은 가독성이 떨어진다.

http://localhost:3333/user?id=89&password=1234

이방식을 이렇게 변환할수도 있다

http://localhost:3333/user/89/1234

app.get 에서 라우터명에 쿼리명을 미리 지정하는것인데 이런방식으로 코드를 변환 하면 된다.

    app.get('/user/:id/:password', callback);

POST

앞서 POST 는 Express 에서 조금 특별하다고 설명 했다.

데이터 핸들링을 활성화하는 Router 미들웨어에 앞서 bodyParser 미들웨어를 선언

해야 한다.

bodyParser 에 대한 미들웨어 설명은 1번째 포스팅을 참고 해주기 바란다.

bodyParser 에 options 로 keepExtensions 와 uploadDir 를 설정할수 있는데

keepExtensions 는 임시파일에 확장자를 포함할지 여부 (기본값 false);

uploadDir 은 임시 파일이 업로드될 위치를 정의한다.

GET 방식에서완 다르게 POST 방식에서 문자열 접근은 req.body로 한다.

파일에 대해서 공식문서에 따르면

익스프레스 4.x 버전부터는 더이상 req.files 를 기본적으로 사용할수 없게 되어서

busboy, multer, formidable, multiparty, connect-multiparty, or pez. 등에

미들웨어를 사용해야 된다고 명시 하고 있다.

각 미들웨어 마다 file 을 호출하는 방식이 다른경우도 있고 같은 경우도 있다.

이것저것 써본 봐로는 multer 를 추천하고 싶다.

POST 신호와 callback 사이에 middleware 를 끼워넣는것은 똑같은데

connect-multiparty 보다 직관적이고 레퍼런스가 많다.

이해의 편의성을 위해 코드에선 connect-multiparty 를 사용했다.

var multipart = require('connect-multiparty');
var multipartMiddleware = multipart();

router.post('/file',multipartMiddleware,function(req, res) {
    var nickname = req.body.nickname;
    var message  = req.body.message;
    var imgfile  = req.files.image
    res.redirect('/');
});

req.files 가 정의하고 있는 객체는 미들웨어마다 조금씩 다르다.

간단한 파일 업로드를 해보자.

다음코드를 /file POST 신호의 callback 함수 안에 추가한다.

    var target_path = __dirname + '/../public/images/'+ req.files.image.originalFilename;
    var temp_path   = req.files.image.path;
    fs.readFile(temp_path, function(err, data) {
        fs.writeFile(target_path, data, function(err) {
            res.redirect('/');
        });
    });

target_path 에 주목할 필요가 있는데 __dirname 은 현재파일이 위치한 경로를 보여준다.

참고로 __filename 도 있다.

그런데 문제가 있다.

이코드는 routes/index.js 에 정의되어있기때문에 public/images/에 저장하기 위해선

__dirname에 상위 경로를 찾아가야한다.

다음과같이 경로를 설정하면 __dirname 의 parent 경로를 호출할수 있다.

/..public/images/

Cookie

Cookie 역시 POST 를 사용하기위해 Router 에서 앞서 먼저 선언된 bodyParser 처럼

cookieParser 가 Rotuer 보다 먼저 설정되어야 한다.

app.use(express.cookieParser());

쿠키 사용은 키, 벨류형식으로 매우 간단하다.

쿠키 쓰기

res.cookie('name', 'hello')

쿠키 읽기

req.cookies.name

쿠키 수정

res.cookie('name', new_value)

쿠키 삭제

res.clearCookie();

쿠키 삭제는 설정해놓은 날짜에 도달하면 삭제되거나 정확한 도메인 이름과 경로 옵션을

사용하지 않으면 삭제되지 않는다.

쿠키의 생성방식에 따른 삭제 방식을 보여주고 있다.

생성 삭제
res.cookie('name','hwang') res.clearCookie('name')
res.cookie('name','hwang',{path: '/name'}) res.clearCookie('name',{path:'/name'})
res.cookie('name','hwang',{sign: true}) res.clearCookie('name')

signedCookie

말그대로 서명 있는 쿠키이다. 서명을 포함시켰기때문에 조금더 안전하다.

서명이 있는 쿠키를 손코딩으로 수정하면 이를 감지하고 수정된 쿠키를 무효화 시키는

메커니즘을 가지고 있다. 궁금하신분들은 개발자 도구를 통해 값을 변조해보기 바란다.

기존 cookieParser에 파라미터안에 서명할 유니크한 문자열을 넣는다.

app.use(express.cookieParser('ASD123'))

서명 있는 쿠키는 읽을때 req.cookies 객체를 참조 하지 않는다

대신 req.signedCookies 라는 객체를 참조하게 된다.

그래서 name 이란 서명 된 쿠키를 불러오기 위해서는 req.signedCookies.name

으로 호출을 해야 한다.

cookieSession

세션이 들어갔다고 해서 세션인것은 아니다. 여전히 쿠키이다.

쿠키 세션은 쿠키 기반의 스토리지를 구현하며 하나의 세션 키가 아니라 세션 전체를

쿠키에 직렬화한다.

사용법은 cookieParser 밑에 cookieSession 을 선언해주면 된다.

app.use(express.cookieParser('QWE123AZ')) app.use(express.cookieSession(options))

쿠키세션은 4가지 옵션을 객체형태로 넘겨줄수 있는데 key,secret,cookie,proxy 를 설정 할수 있다.

여기서 해당옵션에 대해 다루진 않겠다.

Session

세션스토어는 백앤드에서 세션 데이터를 저장하는 기법이며 세션 스토어 기반 세션은

사용자가 볼수 없는 커다란 양의 데이터를 저장 할수 있다.

session 미들웨어에는 cookieParser 미들웨어가 꼭필요하다.

app.use(express.cookieParser('QWER4234')); app.use(express.session(options));

세션에 설정할수 있는 옵션은 쿠키세션과 동일하고 여기에 store란 옵션이 추가 지정 가능한데

store 의 기본값은 메모리 스토어 이다.

메모리 스토어는 가급적이면 사용을 하지 말아야 하는데 메모리 스토어 와 대체할수 있는 대표적인

스토어 2가지에 대해 간략하게 설명한다.

메모리 스토어

내장형 이고 session 을 정의할때 정의하지 않으면 기본값으로 설정되는 스토어 이다.

RAM을 사용하고 DB 사용이 필요없지만 세션이 증가할때 마다 메모리 소비가 지속적으로 증가한다.

앱이 재실행되면 모든 세션 데이터는 유실되고, 세션 데이터는 하나의 클러스터 내에 있는

앱의 다른 인스턴스들과 공유할수 없다.

레디스 스토어

coonect-redis 모듈을 필요로 한다. 다음과 같은 방식으로 구현 가능하다.

var express = require('express');
var RedisStore = require('connect-redis')(express)
app.use(express.session({ store: new RedisStore({
    host:'127.0.0.1',
    port: 6666,
    prefix: 'sess'
}), secret:'ASDF12QZ'}))

몽고 스토어

레디스와 상당히 유사한 구현 방식을 가지고 있기 때문에 생략 한다.

몽고DB 와 레디스는 추가 포스팅을 할계획이니 이번 포스팅에서 추가적인 내용을

이야기 하진 않겠다.

세션 설정

req.session.name = 'hwang';

세션 읽기

req.session.name;

세션 수정

req.session.name = 'tan';

세션 삭제

delete req.session.name;

세션 삭제는 undefined 나 null 로 값을 설정해도 삭제가 되지않기때문에 객체를 비활성화

시키는 delete 를 이용해 지워야 한다.

전체 세션 삭제는 req.session.destory() 를 호출한다.

cookieSession 은 destory() 함수를 지원하지 않으니 참고 한다.

End.. And..

그밖에 불안정하거나 다루지 않는 내용들이 있다.

  1. 벤치마킹은 siege 로 한다
  2. 프로덕션 환경은 템플릿과 css전처리기를 캐싱하고 메모리크기에 제한을 주며 에러메서지가 간결해짐
  3. 지속적인 가동 보장은 forever 라는 모듈 사용
  4. 리버스 프록시 - 공부해야함
  5. 클러스터 처리 - 서버쪽으로 진출할 계획이되면 향후..
  6. 예외 처리 - Promise 에서 then().catch() 처리 하면되는것 아닌가..?

익스 프레스 모듈을 지금 이상 다룰일이 있나 싶다.

현재 webpack 과 express 를 이용한 서버 코드를 구성하는데 이정도 지식만 으로도

큰 문제가 없기 때문이다.

지금까지 포스팅한 익스프레스에 대해 공부한 코드들은 모두 여기에 있다.

부트스트랩을 써서 대충 만들어봤다. 가동했을때 이미지는 이렇다.

 

repository clone 을 통해 가동 시켜보면서 공부하면 조금이나마 도움이 더 되지않을까 생각한다.

'BackEnd > Express.js' 카테고리의 다른 글