Nodejs 테스트 코드 작성

테스트 코드 작성

  • 테스트 코드 작성
    • 코드로 테스트하기
    • 테스팅 자동화
  • 테스트 코드 작성 모듈 ?
    1. assert
    2. should
    3. mocha

assert module

  • 특징?
    • Nodejs 기본모듈 (설치 X)
  var assert = require("assert")
  • 테스트하기
/Boolean Test 참 , 거짓
assert.ok(value[, message]);

/동등 테스트 equal , ===
assert.equal(actual, exprected[, message]);

/에러 발생
assert.throws(block[, error][, message]);

Ok Test 예제

/성공코드
var assert = require("assert"); / module loading

var boolVal = true;
assert(trueValue);
/ or
assert.ok(boolVal, "에러시 내보낼 메시지다.");

/실패코드
/ 에러발생시 프로세스가 죽고 에러와 등록된 메세지 출력
var boolVal2 = false;
assert(boolVal2, "에러났는데 ?");
  • 출력되는 에러메세지 예
throw new assert.AssertionError({
  ^
AssertionError : 에러났는데 ?
})

Equality Assertion 예제

var assert = require('assert');

/ 같은 객체 비교
assert.equal(actual, expected[, message]);
/ 내용 비교
assert.deepEqual(actual, expected[, message]);
/ === 비교
assert.strictEqual(actual, expected[, message]);
  • 테스트코드 작성 예제
var intVal = 9;

assert.equal(intVal, 9, '다르다');
assert.equal(intVal, '9', '다르다');
assert.deepEqual(intVal, '9', 'deepEqual 다르다');
assert.strictEqual(intVal,'9','strictEqual 다르다'); / AssertionFail

should module

  • github : /github.com./tj/should.js/
  • BDD 방식의 assert 작성
$ npm install should

테스트 코드

  • should
var intVal = 5;
intVal.should.ASSERTmethod();

/assert 함수
intVal.eql(비교변수) / == 두개
intVal.equal(비교변수) / === 세개
intVal.startWith(string), intVal.endWith(string)

/chain 방식으로도 사용가능
intVal.be.ok
intVal.be.type(비교변수)
intVal.have.properties(propName1, propName2, .....)
  • 예제코드

var num = 5; num.should.equal(5); /3단계비교 var str = "hello" str.should.equal("hello");
  • 값 비교 실패시
var str = 'taewoong'
str.should.equal("fail");


/실패 메세지
AssertionError : expected 5 to be 4
  • 객체 동등비교
    • .eql : 컨텐츠 비교 / ==
    • .equal : strict equal. === 비교
var obj = {
  value : 10,
}

obj.should.eql({value:10}); / success
obj.should.equal({value:10}); /Assert 실패, ===
  • 체인 방식의 Assertion 예제
var str = "taewoong";
str.should.startWith("t").and.endWith("g");
/ str 의 시작 문자가 t로 시작해야하고 g로 끝나야한다.

Test Framework mocha 알아보기

  • 홈페이지(/mochajs.org)
  • 설치
$ npm install -g mocha
  • 테스트
    • 테스트 자동화 리포팅
    • TDD, BDD
    • 다른 Assert 라이브러리와 결합 사용

mocha를 BDD 기반 작성

describe("Calculator" , function(){ /계산기는
  if("should add" ,function(){
      /add 라는 동작에
      /assertion 로직 기입
  });
  if("should minus" ,function(){
      /minus 라는 동작에
      /assertion 로직 기입
  });
});
  • 개별테스트
/ assert 코드
it("task spec1", function(){
    assert.equal(value, expected);
});


/should와 사용
it("task spec2" , function(){
    value.should.equal(exprected);
});

/ 비동기 행위 테스트코드
it("async task spec3", function(done){
    asyncApi(value , function(){
        value.should.equal(expected);
        done();
    });
});
  • 후크 (hook)
/ 모든 테스트 시작전, 테스트 종료 후
before(function() {});
after(function() {});


/개별 테스트 시작 전, 개별 테스트 종료 후
beforeEach(function() {});
afterEach(function() {});
  • BDD 인터페이스 (예제코드)
describe("Calculator", function(){
    var calculator;

    before(function(){
        calculator = new Calculator();
    });

    after(function() {});
    beforeEach(function() {});
    afterEach(function() {});

    /tests
    it("should add two value", function(){
        /개별 테스트 코드
    });
});
  • 테스트 동작
테스트 코드 실행명령
$ mocha test.js
  • 테스트 코드 관리시에는 test폴더를 생성해서 메인 로직과 test 코드를 분리할 필요가 있다.
$ mocha
/명령을 주면 모든 test폴더안에 있는 모든 test 코드를 실행 시킨다.

mocha 를 TDD 기반으로 작성하기

suite("SUITE NAME", function() {
    test("UNIT TEST", function(){
        assert.equal(....);
    });
});
  • hook
    • suiteSetup(모든 테스트 시작전), setup(개별 테스트 시작전)
    • suiteTeardown(모든 테스트 시작후), teardown(개별 테스트 시작후)
  • TDD 기반 테스트 동작

$ mocha -u tdd TESTCODE.js
  • 테스트 작성은 별도로 공부를 해야함(책하나사서 공부해야할것같네요)

  • TDD 인터페이스

suite("Calaulator", function(){
  var calculator;

  suiteSetup(function(){ /테스트 시작전
      caculator = new Calculator();
  });
  suiteTeardown(function(){}); / 테스트 시작후
  setup(function() {}); /개별테스트 시작전
  teardown(function(){});/개별테스트 시작 후

  test("Add", function(){
      var value = calculator.add(1, 2);
      assert.equal(value,3,"1 + 2 =3");
  });

  test("Minus", function(){
      / minus 테스트 코드
  });
});
  • 실행 명령 package.json에 등록

{ ... "scripts":{ "test" : "mocha testAll" }, ... }
  • 터미널 실행
$ npm test
/ npm test라고 명령을 주면 package.json 파일을 읽어서 test라는 명령에 있는 값을 터미널에서 실행시킴

포스팅 마치며..

  • 입문자의 입장으로서 단위테스트에 대한 부분이 아직 잘와닿지않는다. 아직부족한부분이 많다는걸 느끼게된다.

  • 위 포스팅 내용은 T아카데미 서버개발 강좌를 참고하여 작성하였습니다.

TODO

  • 테스트 케이스 작성하면서 CSS관련 컴포넌트 만들어보기
  • 단위 테스트 및 테스트 자동화에 대한 학습

Nodejs 디버그

디버그

  • Log Message 출력
console.log("일반 로그 출력");
console.info("정보성 로그 출력");
console.warn("경고용 로그 출력");
console.error("에러 로그 출력");
  • 로그 외 다른 디버깅 방법
    • 코드 단계 별 동작 확인
    • 실행 멈춤 – 브레이크 포인트
    • 특정 시점에서의 스택 상황
    • 스코프 내 변수의 값 확인
  • 디버깅 모드로 동작시키기
    $ node--debug
    $ node--debug-brk
    
  • 디버깅 모드로 동작 중
    $ node--debug server.js
    msg : Debugger listening on port (portNumber)

Node-Inspector

  • Webkit 기반 브라우저에서 Node.js app 동작 디버깅

  • Github : /github.com/node-inspector/node-inspector

    $ npm install -g node-inspector
    
    • 디버깅 시작
    Node-debug[-brk] app.js
    
    • Node-inspector 실행, url 복사
    • 웹브라우저로 url 열기

    • 실행정보

    • CallStack
    • Variables
    • Breakpoints

    • Atom 혹은 VScode 처럼 IDE 자체에서 디버그를 지원해주는 경우도 있습니다.

(989) 690-3832

보안

  • 사용자 가입과 로그인
    1. 가입 : 사용자 정보를 저장
    2. 로그인 : 사용자 정보를 전송
  • 비밀번호 저장
    • 비밀번호 암호화 저장
    • 복호화가 필요없음 ( 복호화 : 암호화 된 데이터를 다시 원본데이터로 복구시키는 과정 )
  • 네트워크로 데이터 전송
    • 데이터 암호화 – 전달
    • 전달 받은 암호화된 데이터 복호화

암호화 종류

  • 복호화가 불가능한 암호화(해쉬 알고리즘 이용)
  • 복호화가 가능한 암호화

암호화/복호화

  • 암호화(encryption)
    • 원본 데이터를 변조해서 알 수 없도록 변환
  • 복호화(decryption)
    • 암호화된 데이터에서 원본데이터(평문) 얻기
  • 사용자 비밀번호 암호화 저장
    • 복호화 불필요
    • 해시(hash) 알고리즘 사용
  • 사용자 개인 정보 전송
    • 복호화 필요
    • 대칭/비대칭 키 암호화
    • HTTPS

HASH 알아보기

  • 해시란?(hash)
    • 단방향으로 생성하는 값, 함수
  • 해시 특징
    • 고정 크기의 해쉬값
    • 입력값이 같으면 해시값도 같다.
    • 해시값이 같아도 입력값 (평문)이 같다는 보장은 없다.
  • 주요 hash 알고리즘
    • MD5(Message Digest5)
      • 1991년
      • 128bit 암호화 해시 함수
      • 결함 발견 – 보안 용도로 사용을 권장하지 않음.
      • 사용 예 : fingerprint
    • SHA(Secure Hash Algorithm)
      • SHA0, SHA1, SHA2(256, 512, …)
      • SHA1 : 160bit
        (SHA1 또한 최근의 보안상의 결함으로 여러곳에서 지원하지 않고있음)
    • 해시 사용예

    • 전송 데이터 에러 검사 : Checksum
    • 다운로드 받은 후에 전송값을 hash로 변환에서 다운받은 파일이 변조등이 있는지 확인하는 과정

    • 해시 사용예2

    • 사용자 비밀번호 저장
    • 암호 대신 비밀번호의 해쉬값 저장

hashpassword

  • 위에 예제를 통한 사용자 인증시
    app.post("/login" ,function (req, res) {
        var password = req.body.password;
        var user = user.findOne(username);
        if( hash(password) === user.password ){
            / 인증 성공
        }
    });
    
  • 해시 암호 공격
    • 사전, 자주 사용하는 암호 기반의 해쉬 테이블(레인보우 테이블) 준비
    • 사용자의 해시 암호와 비교
    • 무차별 입력(brute force), 룩업 등

hash rainbowtable

  • 위와같이 해쉬값 끼리 비교해서 비밀번호를 얻어낼 수 있음.
    • 해결방안 ?
    • 사용자의 암호에 소금(SALT)치기
    • HASH(사용자 암호 + 임의의 문자)
    • HASH(“charlie” + “!”);
    • 문자열 하나만 더 추가 되어도 Hash값은 완전히 바뀌기 떄문에 레인보우 테이블 사용 불가

    • SALT사용시 주의사항 ?

  • 사용자마다 다른 SALT 사용
  • SALT는 충분히 길게

    • 짧은 SALT ▶ 레인보우 테이블 준비가능
    • 예측 가능한 SALT 사용하지 말 것

    • (입력값 + SALT)의 해쉬 === 데이터베이스에 저장된 해쉬

app.post("/login" ,function (req, res) {
    var password = req.body.password;
    var user = user.findOne(username);

   if( hash(password + user.salt) === user.password ){
        / 인증 성공
    }
});

암호화 모듈

  • crypto : 기본모듈
  • bcrypto : 확장 모듈
  • 설치

    $ npm install bcrypto

crypto module

  • hash 기능
/hash 알고리즘에 대한 기능들을 얻어냄
crypto.getHashes();

/hash 알고리즘을 인자로 넘겨 hash를 생성함
crypto.createHash(algorithm);

hash 알고리즘 list
md5, sha1, sha256, sha512
  • hash 값 만들기(예제code)
var sha256 = crypto.createHash("sha1");
sha1.update("hello");
var digest = sha1.digest("hex");

/5d41402abc4b2a76b9719d911017c592
console.log("sha256 : %s" , digest);
  • crypto 모듈의 hash와 Salt
function signup(id, password, name) {
    var sha256 = crypto.createHash("sha256");

    /Salting
    var salt = crypto.randomBytes(5).toString("hex");
    sha1.update(password + salt);
    var hashed_password = sha1.digest("hex");
}
  • 사용자 입력 암호와 저장된 값 비교
function login(id, password) {
  var sha256 = crypto.createHash("sha256");
  var salt = user.salt;
  sha1.update(password + salt);
  var digest = sha1.digest("hex");

  /Salting한 암호와 사용자 암호 비교

  if ( user.passwrod === digest ){
      /로그인 성공~
  }
}

암호화

  • 암호화의 종류?
    • 대칭 암호 (symmetric cryptography)
    • 비대칭 암호(Asymmentric cryptography)

대칭 암호(symmetric cryptography)

  • 특징
    • 같은 키로 암호화/복호화
    • 키를 분배해야한다.
  • 대칭암호화 구조

대칭암호화 구조

  • 알고리즘
    • DES( Data Encryption Standard )
      • 56bit
      • AES로 대체
    • AES( Advanced Encryption Standard )
      • 레인달(Rijndael)알고리즘

비대칭 암호(Asymmentric cryptography)

  • 특징?
    • 서로 다른 키( 개인키, 공개키 )로 암호화/복호화
    • 개인키(private key) : 공개 안함
    • 개인키로 암호화 ▶ 공개키로 복호화
    • 공개키로 암호화 ▶ 개인키로 복호화
    • 대칭 암호에 비해서 느리다.
  • 비대칭 암호화 구조
    비대칭 암호화 구조


Crypto module 암호화 / 복호화 클래스

  • 암호화 클래스 : Cipher
var cipher = crypto.createCipher();
cipher.update();
cipher.final();


/암호화 사용방식 예제 (AES128 알고리즘)
var key = "my Secret key";
var cipher = crypto.createCipher("aes128", key);
/메시지 암호화
var message = "hello world";
var encrypted = cipher.update(message, "utf8","hex");
encrypted += cipher.final("hex");
  • 복호화 클래스 : Decipher

    var decipher = crypto.createDecipher();
    decipher.update();
    decipher.final();
    
    /복호화 사용방식 예제 (AES128 알고리즘)
    var decipher = crpto.createDecipher("aes128" ,key);
    var decrypted = decipher.update(msg, "hex", "utf8");
    decrypted += decipher.final("utf8");
    
    

보안서버 만들기 (HTTPS)

  • HTTPS ? (HTTP over SSL)
    • 데이터 암호화 통신
  • SSL ?
    • 넷스케이프 SSL → IETF의 TLS
    • 대칭키 암호화 방식
  • SSL 인증서
    • 서비스를 제공하는 서버의 정보
    • 신뢰성 있는 인증 기관(CA)의 서버 인증
    • 서버 공개키 : 비대칭 암호화용
  • 인증서 발급 ?
    • 공인된 인증 기관에서 인증서 발급
      • 유료입니다..
      • 인증 기관 : Verisign, Comodo
    • 사설인증서 발급
      • 키와 인증서 생성 프로그램 : openSSL
      • 홈페이지(/www.openssl.org)
      • 인증기관에서 인증을 받은게 아니기때문에 warning을 발생 시킵니다.
    • 사설 인증서로 보안서버 만들기

  • 만들기 위해 필요한것 ?

    • 키(key)
    • 인증서
  • 인증서 발급 단계
    1. 키 생성
    2. 키에서 인증서 발급 요청(csr) 생성
    3. 인증서 발급 요청에서 인증서 발급
  • open SSL 설치후
    • private 키 생성

    $ openssl genrsa -out key.pem 2048

  • 인증서 발급요청

    $ openssl req -new -key key.pem -out req.csr

  • 인증서 발급 승인

    $ openssl x509 -req -in req.csr -signkey key.pem -out cert.pem -days 365

  • 서버 생성
    • https 모듈 사용
    • 보안 서버 생성
var https = require("https");
https.createServer(option ,[Request Listener])

options
  key
  cert
  passphrase : 개인키 암호
  • 서버생성 예제
var http = require("http"),
https = require("https")

var options = {
  key : fs.readfileSync("./key.pem"),
  cert : fs.readfileSync("./cert.pem")
};
https.createServer(options, function (req, res) {}).listen(3001);

http.createServer(options, function (req, res) {}).listen(3000);
  • Express 사용 예제

var express =require("express"), http = require("http"), https = require("https") var app = express(); http.createServer(app).listen(3000); var options = { key : fs.readfileSync("./key.pem"), cert : fs.readfileSync("./cert.pem") }; https.createServer(options, app).listen(3001);

보안서버 의무화

  • 영리 목적으로 하는 개인정보 수집 서비스는 보안서버가 의무화 되어있습니다.
  • 무료
    • /www.startssl.com
    • /letsencrypt.org
  • 유료
    • verisign(/www.verisign.com/)
    • symantec(/www.symantec.com/)
    • comodo(/www.comodo.com/)

passport를 통한 보안인증

인증

  • 인증 작성하기
    • 서비스내 직접 인증 기능 작성(Local Auth)
    • 3자 인증 기능 사용(OAuth)
    • OpenID

로컬 인증(Local Auth)

  • 로컬 인증
    • 서비스 자체에서 사용자 가입
    • 사용자 로그인 기능
    • 사용자 정보 관리
  • 로컬 인증시 필요한 점
    • ID/PW가 서버와 클라이언트 메세지에 담겨서 이동
    • 서버에 ID/PW 저장
    • 사용자 정보 암호화
    • 보안 통신 필요 : HTTPS

3자 인증

  • 3자 인증(OAuth)
    • 다른 서비스에 등록된 사용자의 인증 정보 사용
    • 직접 가입/로그인 절차가 없음
    • ID/PW 노출 위험 적다.
    • 다른 서비스에서 토큰 발급

절차

  • 새로운 서비스 사용하기
    • 새로운 사용자라면, 인증하라고 요청
    • 서비스 키 제공(Client_id, secret)
  • 가입된 서비스에 3자 인증 요청
    • 가입된 서비스에 인증
    • 인증 정보를 새로운 서비스에 전달
  • 가입된 서비스에 인증 상황 문의
    • 인증된 사용자인지 문의
    • 서비스 사용 가능

Passport

  • 인증 모듈
    1. passport
    2. everyauth
  • passport(/passportjs.org)

  • 설치

$ npm install passport
  • 절차

passport 절차

  • __Module 로딩과 초기화___
    var passport = require("passport");
    app.use(passport.initialize());
    
  • __Strategy 설정___

    var Strategy = require("passport-strategy").Strategy;
    passport.use(
      new Strategy(function(username,password , done){})
    )
  • 다양한 인증 제공

    1. LocalAuth
    2. facebook, twitter, google
    3. kakao talk 등등
  • 인증 요청

  app.post("/login", passport.authenticate("local"));
  • 인증 성공시
    • 성공 메세지와 코드
    • 성공 페이지 이동(웹)
  • 인증 실패시
    • 실패 메세지와 코드
    • 로그인 페이지(웹)
  • session 기록과 읽기
  /쓰기 (기록)
  passport.serializeUser(function(user,done){});
  /읽기
  passport.deserializeUser(function(id,done){});
  • 요청 마다 세션 기록과 읽기

    • passport.authenticate 이후 세션 기록(serializeUser)
    • 일반 요청마다 세션에서 읽기(descrializeUser)

    • 세션에서 읽어온 데이터

  request.user
  /passport를 사용했을때만 프로퍼티가 생성됨

Local Auth

  • 로컬 인증용 Strategy
 passport-local
  • 설치
 $ npm install passport-local
  • module 로딩과 Strategy 로딩
  var LocalStrategy = require("passport-local").Strategy
  • 인증 Strategy
  var strategy = new LocalStrategy(Option , function(username , password , done){});]

  options{
  /passReqToCallback: 요청객체 (req) 를 파라미터로 전달
  /usernameField, passwordField : 사용자 ID, Password에 해당하는 필드 이름 등록
  / form 양식내에서 보낸 req.body 안에 파라메터를 함수의 인자로 전달해준다.
  }
  • Strategy의 인증 기능 구현
  • var strategy = new LocalStrategy(OPTION, function(username , password, done){})
    
  • 인증 함수 구현

  • 인증 성공

    done(null, USER-INFO)
    
  • 인증 실패
    done(null , false , FAILURE-INFO)
    
  • 예제코드
    var LocalStrategy = require("passport-local").Strategy;
    
    var strategy = new LocalStrategy(function(username, password , done){
    
      /인증 과정함수작성
      if( username && password ) {
    
        /인증성공시
        var userinfo = {name : "taewoong" , email : "taewoong@gmail.com"};
        return done(null, userinfo);
      }
    
      /인증 실패시
      done(null, false, {message : "incorrect ID/PW"});
    }
    );
    
    / 패스포트에 적용하기
    passport.use(strategy);
    
  • 인증 요청과 인증 함수 동작
    • 인증 요청 (method : post , url : /login)
    • Local Strategy의 인증 함수 동작
    passport.authenticate(Strategy, Option, Callback);
    /*
    options
    session : 세션 사용여부 default = true
    successRedirect, failureRedirect : 인증 성공/실패시 Redirect 할 주소
    */
    
    • 인증 함수동작 방식
    passport.authenticate(LocalStrategy , function(err, user, info){
        if( err ) return; /Error
    
        if ( user ){
            /성공
            console.log("로그인 성공~",user,info);
        } else {
            /실패
            console.log("로그인 실패",user,info);
        }
    });
    
    • 인증 요청처리 방식(웹 브라우저)
    app.post("/login", {successRedirect : "/myhome", failureRedirect : "/login"});
    
    • 인증 요청처리 방식(모바일 앱)
    app.post("/login", passport.authenticate("local"), function(req, res){
      res.end("로그인 성공");
    });
    /미들웨어 함수 콜백을 스택형태로 쌓아서 로그인성공시 다음 미들웨어로 넘어갈수 있도록하고 로그인 실패시 자동으로 status code 401(권한 없음), Unauthorized 이 반환된다.
    
    • 인증 정보 유지 – 세션
      • 인증 성공 ▶ 세션 기록

        passport.serializeUser();

      • 클라이언트 요청 -> 세션에서 인증 정보 읽기

        passport.deserializeUser();

      • 세션에 기록된 사용자 정보 접근 방법

        request.user

    • 예제코드

    /사용자 정보저장
    passport.serializeUser(function(user, done){
        done(null , user);
    });
    /세션에서 사용자 정보읽기
    passport.deserializeUser(function(user, done){
        done(null , user); / 이 시점이후 req.user 사용가능
    });
    
    • 세션 저장 정보 형태
    /사용자 정보저장
    passport.serializeUser(function(user, done){
        done(null , user.id); /사용자 id만 저장
    });
    /id에서 사용자 정보찾기
    passport.deserializeUser(function(id, done){
        var user = findUser(id);/id로 정보 찾는 함수
        done(null , user); / user에 등록
    });
    

세션 사용 설정 코드

/*
모듈 로딩생략
*/
var app = express();
/세션 모듈 설정

var session = require("express-session");
app.use(session({
    secret : "Secret Key",
    resave : fasle,
    saveUninitialized : true
}));

/패스포트 설정
var passport = require("passport");

app.use(passport.initialize());
app.use(passport.session());

Facebook OAuth

  • Strategy : passport-facebook

    $ npm install passport-facebook

  • 페이스북에 서비스(앱) 등록

  • 페이지 이동 발생

    • 인증 요청 : 서비스 → 페이스북 페이지로
    • 사용자 승인/거부 → 페이스북 페이지 → 서비스로
    • redirect 주소 필요

등록

  • 앱 식별 정보와 비밀키 : APP ID, APP Secret
  • FaceBook 인증 함수
    var FacebookStrategy = require("passport-facebook").Strategy;
    var fbStrategy = new FacebookStrategy({
        clientID : FACEBOOK_APP_ID,
        clientSecret : FACEBOOK_APP_SECRET,
        callbackURL : CALLBACK_URL
    },
    function(accessToken, refreshToken, profile, done){
    });
    passport.use(fbStrategy);
    
  • 간단한 요청 처리
    • 로그인 요청
    /HTML
    <a href="/auth/facebook"> 로그인 버튼</a>
    
    /Server Nodejs
    app.get("/auth/facebook", passport.authenticate("facebook", {scope : "email"}));
    
    • 인증 요청시 scope
      • 읽기 권한 : email, public_profile, friend
      • 쓰기 권한 : create_content,…
  • 과정
    1. 첫로그인 요청
    2. Facebook 인증 권한 요청 페이지로 전환
    3. 권한 인증 승락/ 거절후 페이지 이동 : callbackURL(위에서 설정해준 CALLBACK_URL)
  • 사용자 승인 후 사용자 정보 : token, profile
    var FacebookStrategy = require("passport-facebook").Strategy;
    var fbStrategy = new FacebookStrategy({
      clientID : FACEBOOK_APP_ID,
      clientSecret : FACEBOOK_APP_SECRET,
      callbackURL : CALLBACK_URL
    },
    function(accessToken, refreshToken, profile, done){
    / 사용자의 profile 객체 profile
    var id = profile.id;
    var name = profile.displayName;
    var email = profile.emails[0].value;
    /사용자의 정보를 일부 DB에 담거나 가지고있을수있음
    });
    passport.use(fbStrategy);
    
  • 모바일 앱
    • SNS 인증 – FaceBook 앱에서 담당
    • 콜백 불필요
    • 앱간의 이동이기때문에 페이지를 이동할필요가 없음 (콜백 URL이 불필요)
    • 모듈이 다름
  • 모듈
    >passport-facebook-token Strategy

포스팅 마치며

  • 아직 개발초보여서 HTTP프로토콜 조금아는수준이 되었지만 보안과 프로토콜의 대해서 웹개발자는 떌래야 땔수없는 관계같습니다. 기회가 되면 조금더 깊게 배워보는 시간을 가져보고싶네요.

  • 위 글은 T아카데미 Nodejs 서버개발 강의를 바탕으로 작성된 포스팅입니다.

2268837194

Cookie

  • 클라이언트의 활동 추적하기
    • 로그인 하지 않은 사용자가 쇼핑몰을 사용한다.
    • 쇼핑몰에서 상품을 장바구니에 넣으면?
    • 다음에 쇼핑몰에 방문했을 때, 장바구니는?
    • 장바구니 내용을 브라우저에 기록.

Cookie 다루기

  • 서버가 웹브라우저에 기록
    1. 상품을 장바구니에 담기
    2. 쿠키에 장바구니 내용 저장
  • 웹브라우저는 쿠키 내용 전송
    1. 서버는 요청에서 쿠키 읽기
    2. 기존에 기록한 내용 확인

HTTP Message 와 Cookie

  • Client(request)
    • 클라이언트 ▶ 서버
    • 클라이언트의 쿠키를 서버로 전송
    • 요청메세지 Header : Cookie
  • 예제
    GET /spec.html HTTP/1.1
    Host : www.example.org
    Cookie : name=value;
    
  • Server(response)
    • 서버 ▶ 클라이언트
    • 응답 메세지에 쿠키 기록을 위한 메세지 작성
    • 메세지 Header : Set-Cookie 필드
  • 예제
      HTTP/1.0 200 OK
      Content-Type : text/html
      Set-Cookie : name=value;
    
  • 쿠키 쓰기
    response.setHeader("Set-Cookie","name=value");
    
  • 쿠키 읽기
    • 쿠키 값 파싱 코드가 필요
    request.headers.cookie / 'name=value'
    

Express 에서 Cookie 다루기

  • 쿠키 쓰기 : Express 기본
  • 쿠키 읽기 : Cookie-parser Module
  • npm & Github
    • /github.com/expressjs/cookie-parser
    • npm install cookie-parser
  • 쿠키 읽기
    request.cookies
    / request 객체의 요청 header안에 Cookie
    

    쿠키 다루기

  • 쿠키 쓰기/ 삭제 : Express 기본
    /쓰기 name , value [,option]
    response.cookie(name, value[,options]);
    /삭제 name [,options]
    response.clearCookie(name[, options]);
    
    options list
    domain : 쿠키가 적용되는 서버
    path : 쿠키가 적용되는 경로
    expire : 쿠키 유효 날짜와 시간
    maxAge : 쿠키 유효기간(ms)
    httpOnly : HTTP 프로토콜에서만 사용
    secure : HTTPS 에서만 사용 여부. type : Boolean
    signed : 서명 여부. type : Boolean
    
  • Cookie parser 사용 예제
    var express = require("express")
    var cookieParser = require("cookie-parser");
    /모듈로딩
    var app = express();
    app.use(cookieParser());
    /미들웨어 함수 등록![cookieheader](/assets/cookieheader.png)
    
    • Cookie 기록하기(Write)
    /쓰기
    response.cookie("last", "2015.8.5");
    response.cookie("viset" , "2");
    
    • Cookie 읽기(Read)
      /읽기
      var last = request.cookies.last;
      console.log(last) / 2015.8.5
      var visit = request.cookies.visit;
      console.log(visit) / 2
      

cookieheader

HTTP 요청과 응답Header안에 Cookie 위와 같이 설정된다.

쿠키 서명(쿠키 변조 방지)

  • 서명된 쿠키 사용하기
    1. Cookieparser 설정
      javascript
      app.use(cookieParser("SECRET_KEY"));
    2. 쿠키 쓰기
      response.cookie("singed" , "OrignalValue" , {signed : true})
      
    3. 쿠키 읽기
      request.signedCookies.signed
      / OrignalValue
      

쿠키의 문제점

  • 메세지의 크기가 커진다 = 느려진다.

  • 다른 웹브라우저로 접속하면 ?(유지할수없음)

  • 보안에 취약 요청과 응답에 따라서 정보가 오고가면서 노출될 위험이 존재함

  • 위 소스코드는 T아카데미 Nodejs 서버개발 강의를 바탕으로 작성된 내용입니다.

2039088347

보안과 인증

  • 인증
    1. 등록된 사용자 식별
    2. 사용자 별 권한
  • 보안
    1. 정보 노출 방지 : 암호화 통신 방법(HTTPS)
    2. 정보 해독 방지 : 데이터 암호화 저장

Session 알아보기

  • 특징 ?
    1. 서버에 정보 저장
    2. 클라이언트에는 세션 식별 정보(세션ID)
    3. 세션ID는 Cookie 사용

    session 모듈 : express-session

    $ npm install express-session
    

    session 작동원리

위와 같이 클라이언트는 Cookie를 통해서session ID를 가지고 서버에 요청을 보내면 서버는 맞는 session 정보와 매핑 시켜주는 구조를 가지고있습니다.


세션 읽고 쓰기

  • 모듈 로딩 과정
    var express = require("express");
    var session = require("express-session");
    
    var app = express();
    app.use(session(option))
    /option Object
    /*
    option list :
    name : 세션 ID의 key name (cookie). default connect.sid
    resave : 변경이 없어도 저장
    secret : session ID 서명
    saveUninitialized : 세션 초기화 전에도 저장
    store : 세션 저장소
    cookie : 쿠키 파서 옵션. 쿠키 파서 없이 사용가능
    */
    
  • 세션 접근
    request.session
    
  • 세션 ID
    var sessionID = request.sessionID;
    
  • 세션 쓰기
    request.session.visit = "123";
    
  • 세션 읽기
    var visit = request.session.visit;
    
  • request header
    session 클라이언트 요청header

위와 같이 session 설정시 cookie를 통해 session ID가 request 요청에 header에 저장된 걸 볼 수 있다.

세션 저장

  • session – 서버에 기록
    1. 서버 재시작 ▶ 세션 기록 삭제
    2. 서버 메모리
    3. 서버 클러스터링
  • 세션을 데이터베이스에 저장 && Session Store 모듈
    • connect-mongo
    • connect-redis
  • MongoDB에 저장 : connect-mongo

    $ npm install connect-mongo

  • connect-mongo 설정코드
    var sessionStoreOptions = {
      url : "mongodb:/localhost:27017/session"
    }
    app.use(session({
      store : new MongoStore(sessionStoreOptions)
    }));
    

  • 세션과 쿠키는 이미 JAVA SERVER를 통해 한번 배운내용이지만 세부적으로 헤더에 어떻게 전송이되는지 또 session을 클라이언트와 검증할때 어떤방식으로 쿠키가 상용되는지 또는 검증되는과정들을 배울 수 있어서 좋은내용이었던것같습니다. 또한 Express 프레임워크에서는 이를 어떤방식으로 다루고 ê·¸ 문법을 통한 로그인, 로그아웃 기능을 간단하게 구현 할 수 있을것같습니다.

  • 위 포스팅은 T아카데미 Nodejs 서버개발 강의를 바탕으로 작성된 내용입니다.

socket.io 를 통한 실시간 웹 서비스

socket.io

웹에서의 실시간 서비스

  • HTTP 방식의 한계와 Socket이 데스크탑 애플리케이션 혹은 모바일에서만 지원되었기때문에 브라우저에서 실시간 웹서비스를 사용하기 위한 다양한 기술시도가 있었으나.
    • ajax
    • polling
    • long poling
    • WebSocket

    위와 같은 기술을 시도했음에도 불구하고 다양한 웹브라우저의 지원되는 차이가 존재하기했으며, 하나의 기술stack으로, HTML5의 표준인 Websocket을 자유롭게 사용하지못했기때문에 socket.io라는 라이브러리가 등장했습니다.

  • socket.io의 서버와 클라이언트

    • Server
    1. HTTP 서버
    2. socket.io 서버
    • Client (웹 브라우저)
    1. HTTP 클라이언트
    2. socket.io 클라이언트
    • 서비스 시작
    1. HTTP 서버준비
    2. socket.io 서버준비
    3. socket.io 클라이언트 요청 – HTML로 응답
    4. socket.io 클라이언트 초기화 및 서버접속

  • 실시간 서비스를 위한 서버 준비

    • Socket.io 서버 생성
    var express = require("express"); / express module
    var http = require("http"); /http module
    
    var app = express(); /express 객체 생성
    
    
    var server = http.Server(app); /http 서버의 request 요청을 express에서 응답하도록 express 객체 전달
    var io = require("socket.io")(server);/socket io서버를 생성하고 http 서버를 전달
    app.listen(8000);
    
    /io.on("connection", callback);
    
    • 서버의 socket.io 클라이언트 html 응답
    app.get("/" , function(req , res){
    res.send(__dirname + "/client.html");
    })
    
    • Socket.io 클라이언트 준비
    1. HTTP 서버에게 socket.io 초기화 HTML 요청
    2. HTML 로딩 – css, js , html 로딩
    3. socket.io 클라이언트 초기화
    4. socket.io 서버 연결
    • Script Module 로딩
    <script src="/socket.io/socket.io.js"></script> /서버에 요청
    <script src="/cdn.socket.io/socket.io-1.3.7.js"></script> /CDN 요청
    /클라이언트 소켓 클래스
    io(url:String , opts : Object):Socket / 전역객체
    
    /소켓 생성, 연결
    var socket = io();
    /Event list
    io.on("connect" , fn);
    io.on("error" , fn);
    io.on("disconnect" , fn);
    
    /재접속 Event ( 서버와 연결이 끊어지면 자동으로 재접속 )
    io.on("reconnect" , fn);
    io.on("reconnectiong" , fn);
    io.on("reconnect_error" , fn);
    

  • 서버와 클라이언트 연결해보기

    • Server
    var io = require("socket.io")(server);
    io.on("connection" , function(socket){/ 응답객체 socket
      console.log("클라이언트가 접속했습니다.");
    });
    
    • Client
    <script src="/socket.io/socket.io.js"></script> / socket io js 파일요청
    var socket = io();
    socket.on("connect", function(arg){
      console.log("server connect");
      /연결성공
    });
    

  • 데이터 교환

    • data 주고 받기 : Event 기반
    • data 이벤트 정의

    • data 전송

      • 이벤트 발생 : socket.emit();
      socket.emit("Event", data);
          /Event 기반의 비동기처리 이므로 callback 패턴을 사용함
      
    • data 수신

    • Event Listener 등록 : socket.on();
     socket.on("Event", function(data){});
     /Event 기반의 비동기처리 이므로 callback 패턴을 사용함
    
  • 예제코드

    • Server
    io.on("connection" , function(socket){
    /클라이언트 소켓의 요청에 따라 연결되었을때
    
    socket.emit("hello" , {message : "Welcome to Socket io ~"});
    /hello 라는 이벤트 data객체에는 message라는 프로퍼티를 담아서 전송
    socket.on("howAreYou", function(data){
        var msg = data["message"];
    });
    /howAreYou 라는 이벤트를 등록하고 data 객체를 받아서 변수에 담는다.
    });
    
    • Client
    var io = IO();
    
    io.on("connect" , function(socket){
    /서버의 응답에 따라서 Socket 연결되었을때
    socket.on("hello", function(data){
      var msg = data["message"];
    /hello 라는 이벤트를 등록하고  data 객체에서 message 라는 프로퍼티값을 변수에 담는다.
    });
    
    socket.emit("howAreYou" , {message : "Welcome to Socket io ~"});
    /howAreYou 라는 이벤트 data객체에는 message라는 프로퍼티를 담아서 전송
    });
    
    • 정리
    1. Event로 메세지 주고받기
    • 서버에 Event로 등록 – 클라이언트에서 Event로 발생
    • 클라이언트 Event로 등록 – 서버에서 Event로 발생

      1. 서버에서의 이벤트 발생
      /소켓 하나에 이벤트 발생
      socket.emit("Direct Event" , {data : data});
      
      /연결된 모든 소켓에 이벤트 발생
      socket.io.emit("Broadcast Event" , {data : data});
      / io.emit 으로도 가능
      / emit은 인자로 javascrip object를 넘김
      

  • 네임스페이스와 룸

    • socket.io 기본 연결은 ?
    • 소켓과 1:1
    • 모든소켓과 통신
      위와 같은 제약이 존재함
    • 1:N 통신하는 방법
    • 개별 소켓과 1:1 통신 N번 반복
    • 네임스페이스
    • 룸
  • 네임스페이스로 socket.io의 연결을 구분해보기

    • 네임스페이스로 구분
    1. 같은 네임스페이스에서만 메시지 주고받음
    2. 기본 네임스페이스 : “/”
    3. 커스텀 네임스페이스 /name-space
    • 코드보기
    /server
    var io = require("socket.io")(server);
    /client
    var socket = io();
    
    
    /----------------커스텀 네임스페이스 --------------
    /server
    var nsp = io.of("/custom-namespace");
    /client
    var nsp = io("/custom-namespace");
    
    • 통신과정(server)
    /기본 네임스페이스
    var io = require("socket.io")(httpServer);
    
    /네임 스페이스
    var system = io.of("/system");
    system.on("connection" , function(socket){
        console.log("System namespace");
    })
    system.emit("message" , "Notice !");
    
    • 통신과정(client)
    /cdn 설정후
    /기본 네임스페이스
    var socket = io();
    
    /커스텀 네임 스페이스를 이용한 연결
    
    var sysNsp = io.("/localhost:port/system");
    sysNsp.on("connect" , function(){
      console.log("System NameSpace connect !");
    });
    system.on("message" , function(data){
        alert("system message : " + data);
    });
    
  • ### 룸(Room) 알아보기
    • 네임스페이스 내 채널
    • 같은 룸에서만 데이터 교환
    • 룸에 입장(join) , 여러 룸에 입장 가능
    • 룸에서 떠나기 (leave)

  1. 룸 접속/나가기
    /특정 룸에 입장
    socket#join(name:string [,fn:function]):socket
    /룸에서 떠나기
    socket#join(name:string [,fn:function]):socket
    
  2. 룸 이벤트
    /특정 룸에만 이벤트 발생
    socket#to(room:String):Socket
    
  3. 룸 입장/떠나기
    • 서버에서 동작

  • Room 예제코드

    • Server
    /socket connection 이후
    var room;
    /채팅방 입장
    socket.on("joinRoom" , function(data){
      /기존 방에서 나오기
      socket.leave(room);
    
      /새로운 채팅방 입장
      room = data.room;
      socket.join(room);
    });
    /채팅 메세지. 룸으로(to) 전송
    socket.on("chatInput" , function(data){
      in.to(room).emit("chatMessage" , "채팅하고싶어요.");
    });
    
    • client
    /socket connection 이후
    
    socjet.emit("joinRoom" , {room : "roomName"});
    
    /채팅 메세지 수신
    socket.on("chatMessage" ,function(data){
      var msg = data["msg"];
      var nickName = data["nick"];
      var str = nickName +" : " + msg;
      /채팅 메세지 누적
      $("#messages").append($("<li>").text(str));
    });
    

포스팅 마치며.

  • 소켓프로그래밍은 초보개발자 입장에서는 매우 어렵게느껴지나 Socket.io는
    이벤트 기반의 비동기 처리의 특성을 통해 javascript를 기존에 알고있던사람이라면은 쉽게 사용 할 수 있도록 만들어진것같다.
    기존에 잠깐 스처지나가는식으로 한번사용해봤었는데 이번에 배워가면서 소켓내에서 1:N간의 통신이 가능하게 해주는 Namespace와 Room의 개념을 새로배웠으며, 이전글의 net모듈을 통하여 소켓프로그래밍을 공부할때보다는 훨씬 더 단순하게 소켓프로그래밍을 할 수 있다.

    • 위 소스코드는 T아카데미 Nodejs 서버개발 강의를 바탕으로 작성된 내용입니다.

6605470195

Nodejs를 통한 Socket 프로그래밍 (실시간서비스)

  • 실시간으로 공연 예약서비스를 만든다 가정.
    1. 사용자가 선택한 공연정보 전달
    2. 예약가능한 공연 날짜와 좌석 정보
    3. 실시간으로 예약가능한 시간과 좌석 정보 반영
    4. 다른 사용자가 예약 -> 예약 좌석 상황 반영
    5. 실시간으로 가능한 자리 선택 후 예약

위와 같은 구성을 HTTP 프로토콜로 할 시에는 ?

  1. 공연 정보와 좌석 정보 요청 – 응답
  2. 자리 선택 후 예약 요청
  3. 다른사용자의 선예약으로 인한 예약 불가 응답

4. 다른 자리 선택 후 예약 요청

HTTP로 실시간 서비스 구현은 매우 힘들다.

  • 이유는 ?
    1. 요청과 응답기반 (요청이 가면 반드시 응답을 해주어야 하는 프로토콜의 구조)
    2. 재요청까지 실시간 변동사항이 반영이 안됨.

    위와 같은 이유때문에 HTTP로 실시간 서비스 작성은 매우어렵다. 그렇기에 HTTP와 호환이 가능한 다른 프로토콜을 사용한다. TCP / UDP


TCP 통신

  • 네트워크 레이어 : Tranport Layer
  • 스트림을 이용한 실시간 통신
  • 소켓을 이용한 네트워크 프로그래밍

실시간 서비스 구현
1. 소켓(Socket)
2. 통신 접점(entry point)
3. 소켓 프로그래밍
– 데이터 그램 소켓 : UDP
– 스트림 소켓 : TCP

TCP UDP
연결 연결 필요 연결 불 필요
신뢰성 신뢰성, 손실된 데이터 재전송 신뢰성 없음
데이터 흐름 혼잡도 제어 없음
속도 UDP에 비해 느림 빠르다
적용 분야 신뢰성 있는 실시간 통신 속도 중시형 실시간 통신 (스트리밍 비디오 / 오디오)
적용 프로토콜 FTP,HTTP,SMTP DNS,DHCP,SNMP

TCP

  • 연결지향이므로 연결 과정 필요
  • 연결 과정 ↓
    1. 서버 소켓 생성, 준비, 대기
    2. 클라이언트 소켓 연결, 소켓간 연결
    3. 데이터 교환
    4. 접속 끊기

TCP 데이터 주고 받기
– 스트림 기반
a. 보내기 : 스트림에 write

b. 받기 : 스트림에 read

UDP

  • TCP와 다른점
    1. 비연결 지향. 연결 과정이 없다.
    2. 신뢰성 없음. 데이터 손실 가능. 패킷 확인, 재전송 없음
    3. 간단한 패킷(데이터 그램)구조. 빠른 전송
    4. 잘못 전송된 내용을 복구할 필요가 없는 실시간 통신(예 스트리밍 오디오/비디오 등)

Nodejs의 Net 모듈

  • 소켓 통신을 위한 기본 모듈 : net
    var net = require("net");
    
    / class
    net.Server /: socket server
    net.Socket /: socket
    
  • 서버 생성 code
    var server net.createServer([options][, connectionListner]);
    
  • 서버 함수
    server.listen(port[,host][, backlog][,callback])/클라이언트 접속 대기
    
    server.close([callback])/추가 접속을 받지않는다.
    
    server.getConnections(callback)/연결 갯수
    
    server.address() / 서버 주소 반환
    
  • 서버의 생성과 연결이벤트
    • code
      /server open callback
      var server = net.createServer(function(socket){
          console.log("Connect Event" , socket.remoteAddress);
      });
    
      / listening Event
      server.on("listening" , function(){
          console.log("Server is listening @", server.address());
      });
    
      / close Event
      server.on("close" , function(){
          console.log("Server Close");
      })
    

소켓 클라이언트

  • 소켓 생성과 연결
    var socket = new net.Socket();/ TCP 소켓은 연결과정이 필요.
    var option = {
      host = "localhost",
      port = 3000
    };
    
    socket.connect(optionObject, function(){/ 연결 함수
    
    });
    /net.Socket 이벤트
    socket.on("connect", fn); / 원격 소켓 연결 이벤트
    socket.on("data", fn); / 읽을 수 있는 데이터 도착 이벤트
    socket.on("end", fn); / 원격 호스트 소켓 종료 이벤트(FIN)
    socket.on("timeout", fn); / 제한시간 초과 이벤트
    socket.on("error", fn); / Error 이벤트
    
    /net.Socket 함수, 프로퍼티
    socket.connect(options[, connectListener]) / 연결
    socket.write(data[, encoding][,callback]) / 데이터 쓰기
    socket.end([data][, encoding]) / 연결 종료 신호 (FIN) 보내기
    socket.setKeepAlive([enable][, initialDelay]) / 연결유지
    socket.remoteAddress, socket.remotePort / 원격호스트 주소 , 포트
    
  • net.Socket 데이터 쓰기
    /클라이언트의 요청
    socket.write("Hello Node~");
    
    
    /서버에서의 대응
    socket.on("data", function(data){
      console.log(data)/데이터 도착 "Hello Node~"
    });
    socket.on("end", function(){
     / 원격 호스트의 종료
    })
    

TCP 기반의 채팅 서비스

  • 채팅 서비스 준비와 연결
    1. 서버 소켓 준비
    2. 클라이언트 소켓 연결
    3. 소켓을 이용한 데이터 교환
  • 채팅 서비스 만들기
    • 1:N 데이터 전달
    • 채팅 관련 명령어 : 닉네임 변경, 1:1 대화, 채팅방 나가기 등등
    • 소켓을 이용한 서비스 : 데이터 전달 + 제어 명령어 전달
  • 클라이언트 접속 이벤트 – 소켓 배열 저장
    var clientList = [];
    var server = net.createServer(function(socket){
    / 소켓을 인자로 받음
    / 클라이언트와 접속한 소켓을 채팅 클라이언트 목록에 추가
    
    var nickname = "Guest" + Math.floor(math.round() * 100);
    /닉네임을 Guest +  1~ 101 까지 랜덤한 값을 지정함
    clientList.push({nickname : nickname , socket:socket});
    /client 라는 배열에 push함
    });
    
    
    /데이터 도착 이벤트 , 모든 소켓에 쓰기
    socket.on("data" , function(data){
    var message = data.toString("UTF-8");
      / 요청에 따라서 받은 데이터를 message 라는 변수에 담음
      clientList.forEach(function(client){
        /클라이언트리스트안이 들어있는 클라이언트 갯수의 배열만큼 반복문을 돌림.
        var socket = client.socket;
          /반복문의 index번쨰의 소켓을 변수에 담아서
          /위에서 받은 message 변수를 다른 클라이언트 모두에게 전달함
        socket.write(message);
          /이럴경우 모두에게 전달되지만 자신의 메세지와 다른사람의 메세지는 구분이 안되니 고려해야함.
      });
    });
    
  • 소켓으로 전송되는 데이터
    • 제어코드
    • 컨텐츠
  • 소켓으로 전송되는 제어코드
      if( message === "\\close"){
          /클라이언트 접속종료
          socket.end();
      }else if( message.indexOf("\\rename") != -1){
          /닉네임 변경요청
      }
    
    

UDP프로토콜을 활용한 실시간 서비스

  • UDP 모듈 : Datagram(dgram);
    1. 기본 모듈
    2. require(“dgram”);
  • class
    • dgram.Socket
  • 소켓 생성
    • type : udp4 , udp6
    • dgram.createSocket(type[, callback]);
  • 함수 (Function)
    /특정 포트와 바인딩
    socket.bind([port] , [,address][,callback]);
    /데이터 전송
    socket.send(buf, offset, length, port, address[, callback]);
    /닫기
    socket.close([callback]);
    /멀티캐스트 그룹 가입
    socket.addMembership(multicastAddress[,multicastInterface]);
    /멀티 캐스트 그룹 탈퇴
    socket.dropMembership(multicastAddress[, multicastInterface]);
    
    • TCP와 다른점
      1. 서버 클라이언트 구분이 없다.
      2. 연결 과정이 없다.
      3. 스트림 방식이 아니다.
    • 소켓 생성

      var socket = dgram.createSocket("udp4");
    
    • 메세지 받기
      var socket = dgram.createSocket("udp4");
      socket.bind(3000);
    
    • 메세지 전송
    var message = new Buffer("hello");
    socket.send(message, O, message.length, PORT, ADDRESS, CALLBACK(err));
    

멀티캐스트 (multicast)

  • 그룹에 포함된 여러 호스트에게 메세지 보내기
  • 그룹에 가입 → socket.addMembership
  • 그룹에 탈퇴 → socket.dropMembership

멀티캐스트용 IP 대역
– D 클래스 대역 : 224.0.0.0 ~ 239.255.255.255


포스팅 마치며.

  • 소켓 프로그래밍 2가지 방식의 대해 알아보았다.
    하나는 TCP ,또 하나는 UDP방식이었고
    TCP와 UDP의 차이점을 잘 기억해두자
    예를 들면
    TCP는 소켓생성 후 연결이 필요하며,(UDP는 필요없음)
    데이터가 신뢰성이 있고(손실된 데이터는 재전송)
    속도는 UDP에 비해 느리다.
    반면에 UDP는 소켓생성이후 연결이 필요없으며,
    데이터는 신뢰성이 없다(이전데이터가 손실되더라도 다음데이터를 전달하게됨.)
    속도 중시형 실시간통신이며 스트리밍(음악/영상)에 많이 사용된다.
    실제로 웹을 하면서 많이 만날일은 없겠지만 각 프로토콜간의 차이와 용도 사용법을 기억해두면 나중에 유용한 정보가 될것이며 필요하게되면 좀 더 심층적으로 공부를 해야 될 내용인것을 느낀다.

  • 위 소스코드는 T아카데미 Nodejs 서버개발 강의를 바탕으로 작성된 내용입니다.

Express 3 (template jade, ejs)

Express template

  • 개요
    • HTML 출력 응답에 헤더가 html일때는 html 응답메세지를 작성해주어야한다. 하지만 응답메세지에 html 작업하는것은 시간도 많이 걸릴뿐더러 협업을 할시에 작성이 불리하기때문에 템플릿을 사용해서 미리 만들어놓은 템플릿 html 파일을 요청메세지에 따라 뿌려주기만 하면됨.

Express 의 template 엔진

  • ejs
  • jade

  • 템플릿 엔진 설정

app.set("views",[템플릿 폴더]);
app.set("view engine" , [템플릿 엔진]);
  • 템플릿에 적용 : 렌더링
res.render(view [, locals] [, callback]);
/locals : 템플릿의 지역 변수로 설정될 데이터
/callback : 렌더링 콜백
/응답 종료
/index 템플릿 파일을 렌더링 한 결과로 응답
res.render("index");


/index 템플릿 파일에 name 이름으로 데이터를 제공
res.render("index", {name : 'iu'});

/user 템플릿에 name 이름으로 데이터를 제공한다. 렌더링 한 결과를 다루는 콜백 함수 정의
res.render("user",{name : "iutt"} , function (err, html) {
  /...
});


ejs

  • ejs 엔진 특징

    • html 태그 그대로 사용
    • 자바서버페이지 뷰템플릿 파일과 비슷한 템플릿 문법을 가지고있음.
  • 실행 코드 작성

<% var value ="hello" %>
  • 여러 줄 작성
<%
var i = 0;
var j = i + 1;
%>
  • HTML ê³¼ 혼합
<% if (value) { %>
<div>hi</div>
<% } %>
  • 값으로 출력
<div> <%= value %> </div>
  • 태그 내 어트리뷰트
<img src="<%=data.image %>">

HTML과 혼합

<% var tag = "h1" %>
<<%= tag %>> TAG 만들기 </<%=tag%>>
  • 템플릿 페이지가 없을 경우
Error : Failed to lookup view "notexist" in views directory "/.../"
/템플릿 엔진 설정 없이 render 사용한 경우
Error : No default engine was specified and no extension was provided
/ 템플릿 내 객체 정의 에러
<%=undefinedVar%>
  • 예제보기(ejs 기준)
var express = require("express");
var app = express();

app.set("views",__dirname+"/views");
app.set("view engine","ejs");

var data = [
  {title : "cat1", image : "cat1.png"},
  {title : "cat2", image : "cat2.png"},
  {title : "cat3", image : "cat3.png"},
];
app.use(express.static("./"));
app.get("/", function(req , res){
    res.render("cat" ,{title : "Cats", cats:data});
});

app.listen(3000);

jade 알아보기

  • 특징 ?
    • 간결한 문서 구조 표현
    • 브라켓 없이 태그만 사용
    • 들여쓰기로 문서구조 표현
  • 시작태그 – 종료 태그 구조 사용 안함 (HTMLê³¼ 구조 비교)

jade                        html
div                         <div>
  ul                          <ul>
    li item1                    <li> item1 </li>
    li item2                    <li> item2 </li>
  p paraasd                    </ul>
                            <p>pararsd</p>
                             </div>
  • attribute (속성 정의)
img(src="image.png" height="50px")
a(href="google.com")
  • 코드 작성
    • -기호를 앞에 실행문
    • =기호를 변수로 출력 출력문

예제

-var title = "jade Example"
h1= title

ul
-for(var i = 0; i < 10; i++){
  li = i
-}
  • HTML 출력
    • = 기호와 문자열 출력. Esacped
    • != 기호와 문자열 출력 . Unescaped
  • HTML 출력 : Interpolation

  • Escaped .#{val}
  • Unesaped : !{val}
/hello <strong>world</strong>
div = "hello <strong>World</strong>"
/Unecsaped String
div != "Unecsaped <strong>String</strong>"
  • if 조건문

    • 기호 없이 사용
    • 들여쓰기로 구문종료
  • 주의사항
    • 템플릿 페이지 ,엔진설정
    • 템플릿 내 지역 변수
    • 인덴테이션으로 문서구조
    • 탭 문자나 스페이중 하나로 통일

  • 위 포스팅은 T아카데미 Nodejs 서버개발 강의를 바탕으로 작성된 내용입니다.

504-520-4570

Express Routing 알아보기

  • Express Framework는 자체적인 라우팅과 Rest api의 메소드들을 제공한다.
  1. Express 라우팅 메소드 보기
HTTP method Express Method
get app.get(“path”, calback aguments request , response)
post app.post(“path”, calback aguments request , response)
put app.put(“path”, calback aguments request , response)
delete app.delete(“path”, calback aguments request , response)
all method app.all(“path”, calback aguments request , response)
  • 요청에 따른 동적 파라메터 얻기
/ request /user/sword
app.get("/user/:item", [Callback]);
/ req.params.item : "sword"
  • 파라미터 값 얻기
req.params.item
  • 다수의 동적 파라미터 사용가능 (참고사항 : 변수의 name은 중복되면 안됨)
  • 동적 파라미터 사용시 주의
    • /user/:item
    • /user/sample
    • 순서에 의해서 항상item을 먼저인식함 이럴경우 sample url 요청검사를 항상 먼저받게해야함

라우팅에 정규식 사용하기

? : 문자 존재하거나 생략
+ : 한번 이상 반복
* : 임의의 문자

정규식 표현 뜻
? 문자 존재하거나 생략
+ 한번 이상 반복
* 임의의 문자

Express route함수 이용하기

  • 메소드의 체인방식으로 라우팅을 연결할 수 있음
  • 사용방법
app.route("path")
  .get(function (req,res){

  })
  .post(function (req,res){

  })
  .put(function (req,res){

  })
  .delete(function (req,res){

  })
  • express.Router() 메소드 이용하기 (라우팅 로직 분리시 용이함)
  • 별도로 route 파일분리후
var app = express()
var router = express.Router();

router.get("/hello", sayhello);
router.get("/howAreYou/:who", sayThankyou);
  • 장점 ? 라우팅 하는 로직을 별도의 파일로 분리할 수 있음

  • 라우팅 로직 별도 분리 (router.js)

var express = require("express")
var router = express.Router();

router.get("/hello", sayHello);
router.get("/howAreYou/:who", sayThankyou);

module.exports = router;
app.use(require("./router")); /route설정객체를 미들웨어 함수 등록
  • 상대 경로 처리 라우터 설정
  • /greeting/hello 경로의 요청
 app.use("/greeting" , require("./greetingRouter"));
  • greetingRouter의 라우팅 코드
router.get("/hello", sayHello);
  • /eat/cooking 경로의 요청 담당 라우팅 모듈
  app.use("/eat",require("./eatingRouter"));
  • eatingRouter 의 라우팅 코드
  router.get("/cooking" , cook);
  • 예제 코드 보기
var express = require("express");
var app = express();

app.get("/:value", work);
app.use(errorHandler);
app.listen(3000);

function work(req ,res , next){
    var val = parseInt(req.params.value);

    / 입력 파라메터 체크
    if ( ! val ){
        var error = new Error("입력값이 숫자가 아닙니다.");
        next(error);
        return;
    }
    res.send("Result : " + val);
}

function errorHandler(err , req, res ,next){
    res.send("에러 발생");
}

  • 위 포스팅은 T아카데미 Nodejs 서버개발 강의를 바탕으로 작성된 내용입니다.

5056598521