Giter VIP home page Giter VIP logo

forum-express's Introduction

forum-express

(project) Community and Forum Service with express.js and node.js

이 repository는 express.js를 활용하여 게시판을 제작하는 미니 프로젝트인 'forum-express'를 진행하면서 작성한 code set입니다. Issue 탭에서 개발 현황인 log(https://github.com/lky473736/forum-express/issues) 를 작성합니다.

저작권은 임규연 (lky473736)에게 있습니다.


This repository is a code set created while working on 'form-express', a mini-project that creates Forum Service using express.js. On the Issue tab, I write the development status aka log(https://github.com/lky473736/forum-express/issues) ).

The copyright of this proj and repository belongs to Lim Gyu-yeon (lky473736).

forum-express's People

Contributors

lky473736 avatar

Watchers

 avatar

forum-express's Issues

forum-express : log 6

forum-express : log 6

미들웨어, routes 파일을 이용한 리펙토링에 대해 기술한다.


미들웨어

  • 요청과 응답 사이에 자동으로 실행되는 함수
  • 특정 api가 시작되기 전에 실행된다고 생각하면 편함
  • 미들웨어 함수의 구성
    • 파라미터 : 요청, 응답, next
    • next 파라미터 : 미들웨어 실행이 끝난 다음 어떻게 진행할 지 여부
    • next() : 정상이니 통과
  • 미들웨어를 여러개 하고 싶을 땐 리스트를 사용한다

router

  • api 하나하나를 라우터라고 부르며, 라우터를 잘 정리하고 리펙토링하는 과정을 라우팅이라고 부른다
  • server.js에 있는 api를 기능별로 routes에 정리하자

forum-express : log 2

forum-express : log 2

forum을 만들 테크는 아래와 같다.

  • node.js : 런타임 프레임워크
  • express : 서버 구현
  • ejs : template engine (서버사이드 렌더링)
  • mongoDB/mongoose : Atlas를 이용한 비관계형DB 구현
  • AWS : 서버 배포
  • socket.io : 채팅 서비스 구현

log 1에서는 express의 기본 틀을 다루었다면 log 2에선 DB 세팅과 ejs 세팅 및 동작 방식 등을 정리한다.


MongoDB vs RDB (관계형 데이터베이스)

  • 세상의 모든 데이터베이스는 두 종류이다
    • 관계형 데이터베이스 : 엑셀이랑 똑같다 (속성, primary key, tuple...)
    • 비관계형 데이터베이스 : 조금 특이한 방식으로 저장한다 (redis나 MongdoDB)
  • MongoDB와 RDB의 차이점
    • RDB는 tuple의 형태로 저장한다 + 정규화 작업을 해주는게 좋다 (현재 테이블의 주제와 맞지 않는 것들을 다른 테이블로 분리하는 것)
    • MongoDB는 Javascript 객체 형태로 데이터를 저장한다 -> Javascript로 작성하는 express를 사용하면서 접근성이 좋아진다 -> 인건비 줄인다 -> 스타트업에서 많이 쓴다
  • MongoDB의 구조
    • Database > Collection > 많은 document
    • document가 일종의 tuple이라 생각하면 된다.
    • 데이터들을 바인딩할 수 있다는 점에서 장점
      코딩애플의 MongoDB
    • 각 document의 프로퍼티 중 최상단엔 각각의 document에 부여된 자동 id가 있다
    • 사용 방식 : 클라우드 호스팅 or local storage
    • 여기서는 Atlas를 써서 클라우드 호스팅할 예정 (AWS)

MongoDB 연결 및 DB에 데이터 저장 / 데이터 불러오기

1) server가 db랑 통신하는 법

  • 유저가 db랑 아무것도 거치지 않고 직접적으로 소통하다간 해킹 위험이 분명 있다
  • 따라서 중간의 검열 역할을 서버가 해주어야 한다
  • mongodb를 통하여 서버의 검열 역할을 해주자
// server.js

const { MongoClient } = require('mongodb');

let db;
const url = 'MongoDB 데이터베이스랑 연결할 수 있는 url';
new MongoClient(url).connect().then((client)=>{
  console.log('DB 연결 성공');
  // client가 url에 접속해서 연결했다면 db연결이 성공한 거다
  db = client.db('forum'); // forum이라는 DB에 접속
    
  // 보통은 db가 연결한 후에 포트를 연다 (listen)
  // 따라서 connect().then 이후에 listen 작업
  app.listen(8080, () => {
    console.log("http://localhost:8080 에서 서버가 실행 중입니다.");
  });
}).catch((err)=>{
  console.log(err);
});

2) �DB에 무언가를 저장할 때

app.get('/post', (요청, 응답) => {
    // db.collection('저장을원하는콜렉션이름').insertOne({정보들});
    // == 저장을 원하는 콜렉션에 정보들을 하나 넣는다 
    db.collection('post').insertOne({sample : 'sample'});
    // sample : 'sample'이라는 document를 post라는 collection에 넣는다
});

// 위의 기능 : /post라는 세부 페이지에 입장하면
// db.collection 중 post라는 collection에
// sample : 'sample'이라는 document를 추가해라

3) DB에 있는 자료를 불러와야 할 때

app.get('/list', async (요청, 응답) => {
    // 응답.send('db에 있던 게시물');
    // db.collection('출력을원하는콜렉션이름').find().toArray();
    // == 특정 콜렉션의 document들을 전부 찾아서 배열 형태로 반환 (async, await 필요)

    // await : 다음 줄을 실행할 때까지 기다리기 (non-blocking i/o이기 때문에 처리가 오래걸리는 코드는 처리완료를 기다리지 않고 바로 다음 줄을 시행하기 때문에)
    // 따라서 db에 있는 자료를 모으기 위하거나 찾기 위해서는 프로그램이 잠깐은 기다려야 한다
    // await 말고도 콜백이나 then 써서 사용할 수는 있으나 mongo에서 계속 await 쓰라니깐 그렇게 한다
    let postlist = await db.collection('post').find().toArray();
    // 그러면 [{}, {}, ...] 이런 형식으로 list에 저장이 된 것이다
    console.log(postlist);

    // ejs 파일을 사용자에게 보내야함
    // 응답.render('ejs 파일명') 
    응답.render('list.ejs', {글목록 : postlist});
});

ejs 세팅 및 작성 방식

  • ejs : html + template engine

  • app.set을 사용하여 express에 세팅해야 함
    app.set('view engine', 'ejs');

  • template engine : html에 database에 있는 데이터들을 넣게 도와주는 라이브러리

  • 서버사이드 렌더링 vs 클라이언트사이드 렌더링

    • 서버사이드 렌더링 : ejs와 같은 template engine을 이용하여 html data binding -> 유저에게 전송
    • 클라이언트사이드 렌더링 : 비어있는 html과 데이터를 유저에게 보냄 -> 유저 브라우저에서 html을 채움 (react 방식)
  • 현재 이 포럼의 구현방식은 서버사이드 렌더링이다.

  • views 폴더에 넣는 것이 관례

  • 서버 데이터를 ejs 파일에 보내려면

      1. ejs파일로 서버데이터를 전송해야 함 -> 응답.render('ejs파일명', {보낼데이터의이름 : find()로불러온데이터} );
      1. ejs 파일 안에서 ejs 문법 사용해서 바인딩하기 ->
        <%= find()로불러온데이터.그데이터의key %>

forum-express : log 1

forum-express : log 1

node.js와 express를 이용해서 간단한 게시판(일종의 커뮤니티)을 구현

  • 예상 개발기간 : 2월 24일 ~ 3월 둘째 주
  • 추후에 알고리즘 학회 전용 온라인 저지 서비스, 수강신청 연습 사이트 구현을 위해 학습하고 구현
  • 대부분의 사이트는 게시판이다 (CRUD) (읽기, 쓰기, 지우기, 로그인, 회원가입...)
  • log를 작성함과 동시에 라이브러리 공부 + 개발일지를 작성

node.js를 쓰는 이유

  • non-blocking I/O를 지원한다는 점 -> 빠르다
    • 일단 client의 요청을 다 받는다 -> client의 요청량이 적은 순대로 순차적으로 업무를 진행한다
    • 보통 django, spring으로 구현하면 일일히 non-blocking을 구현해야 하지만 node.js는 js 특성 상 async같은 걸로 빠르게 구현할 수 있어서 개발 속도가 빠르다 (애초에 자바스크립트가 비동기를 잘 지원한다. 비동기가 non-blocking)
  • 확실히 요즘 해외에서 대세인지라 활용할 수 있는 라이브러리들이 무한하다
  • 하지만 이미지 처리나 동영상 압축같은 무거운 동작들은 여전히 힘들다 (single thread이기 때문이다 -> 따라서 무거운 동작을 처리하기 위해선 spring을 많이 사용하곤 한다)

express 서버 개발 기본 틀 (server.js)

// express 라이브러리를 사용하겠다는 뜻
// 앞으로 app.~~~ 이렇게 사용할 예정
const express = require('express');
const app = express();

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

// app.listen : 컴퓨터에 port를 뚫어놓는 코드
// 첫번째 인자 : port 번호 
// 두번째 인자 : 함수
app.listen(8080, () => {
    console.log('http://localhost:8080 에서 서버 실행중');
});

// app.get : 어떤 페이지 들어가면 어떤 걸 해준다
// 첫번째 인자 : 페이지의 경로 ('/' : 메인 페이지)
// 두번째 인자 : 어떤 페이지에 접속했을 때 실행할 함수 
app.get('/', (요청, 응답) => {
  응답.send('메인 페이지');
});

app.get('/about', (요청, 응답) => {
    응답.sendFile(__dirname + '/about.html');
});
  • static 등록 : css파일이나 이미지 파일 같은 경우엔 express에 먼저 등록을 해야함
    • static : 거의 변동하지 않는 파일들 (css, 이미지파일, 멀티미디어 파일...)
    • static을 public 폴더에 넣고 public을 server.js에 연결한다
    • (__dirname : 현재 위치) + /public
  • app.listen : port 뚫어놓기
    • port : 다른 누군가가 내 컴퓨터에 접속 가능한 일종의 통로
    • 컴퓨터와 컴퓨터는 인터넷이 연결되어 있기만 한다면 서로 접속 가능하다 (구글을 접속할 수 있는 이유도 인터넷이 연결되어 있으며, 우리가 구글의 주소를 알기 때문에 그런거임)
    • 접속하려는 컴퓨터가 port를 뚫어놔야지만 접속이 가능함 (보통 한 컴퓨터에 6만 개 정도 있음)
    • http://(어떤 컴퓨터의 ip주소):(port번호)를 알면 접속 가능함
  • app.get(라우팅) : 특정 디렉토리에 접속할 때 어떤 액션을 취할까
    • 첫번째 인자는 디렉토리 (페이지 만들기)
    • 두번째 인자는 콜백 (첫번째 인자에 들어갔을 때 어떤 액션을 취할까)
    • 콜백 안에 들어가는 함수는 보통 sendFile()을 많이 사용하는데, sendFile 안에는 html 파일의 경로를 삽입 (__dirname+'/(html파일이름)' / 그래야 특정 페이지에 들어갈 때 그 페이지의 html파일을 사용자가 볼 수 있을 거니깐)

forum-express : log 3

forum-express - log 3

글 보기, 글 상세 페이지, 글 작성 기능을 구현하자.

항상 어떤 기능 (feature)을 만들거나 무언가를 debugging해야할 때 무작정 그 기능에 대해 검색하는 것보다는 먼저 한글로 시나리오를 작성하는 연습이 매우 중요한 것 같다.


글 보기 기능

시나리오

  • /list 페이지에 들어간다
  • 제목과 글을 미리볼 수 있는 시스템이 좋겠다
app.get('/list', async (요청, 응답) => {
    // 글 보여줄 글목록을 db로부터 가지고 오기
    let postlist = await db.collection('post').find().toArray();
    console.log(postlist);

    // ejs 띄우기
    응답.render('list.ejs', {글목록 : postlist});
});

글� 상세 페이지

시나리오

  • /detail/~~~~~~ 페이지에 들어간다
    • 이때 ~~~~~~부분은 그 글의 고유한 번호여야만 한다
    • 고유한 번호는 MongoDB document의 _id 프로퍼티를 이용하면 될 듯
    • 만약 사용자가 잘못된 parameter (없는 글)로 접근하면 경고 띄워주면서 다시 /list로 돌아가게끔 하자
app.get('/detail/:id', async(요청, 응답) => {
  try {
    let posting = await db.collection('post').findOne({_id : new ObjectId(요청.params.id)});
    console.log(요청.params.id); 

    if (posting != null) { // 만약 posting이 null이 아니면
      응답.render('detail.ejs', { : posting});
    }

    else { // posting이 null이면
      응답.send("<script>alert('존재하지 않는 게시물입니다.'); window.location.replace('/list');</script>");
    }
  } catch (err) {
    console.log('error occurred');
    return 응답.status(404).send('user error occurred');
    // 404는 유저잘못이라는 뜻임
  }
});

글 작성 기능

시나리오

  • /write 페이지에서 글을 작성할 수 있게 할 텐데, post 형식으로 /add로 글을 전송하자
  • /add로 글을 전송한 후에 insertOne으로 db에 넣으면 될 듯 하다. 이때 예외처리를 할 것
    • 제목이나 내용을 적지 않았으면 경고창 띄우고 다시 작성하게끔 하기
    • 접근이 잘못되었으면 status(500).send(~)
app.get('/write', async(요청, 응답) => {
    응답.render('write.ejs');
});

app.post('/add', async(요청, 응답) => {
    // 요청.body : 유저가 보낸 데이터를 출력 가능 
    // -> body 사용하려면 기본 세팅 필요
    // 요청.query : 유저가 보낸 URL query 데이터를 출력 가능 (query string)
    console.log(요청.body)

    // 예외 처리 (검열처리) => if/else문
    // 만약 제목이나 내용이 없다면 다시 작성하게끔 하기
    if (요청.body.title == '' || 요청.body.content == '') {
      // 다시 작성하라는 메세지와 함께 작성창 다시 로드하기
      응답.send("<script>alert('제목이나 내용이 없습니다. 다시 작성해주십시오.'); window.location.replace('/write');</script>");
    }

    else {
      // 만약에 db가 다운되거나 db가 용량이 딸릴때는 저장하면 안되지 않을까?
      // 에러상황 처리는 try, catch
      try {
        await db.collection('post').insertOne({
          title : 요청.body.title, // 제목 넣기
          content : 요청.body.content // 내용 넣기
        });
        // 다른 페이지로 이동시키기 : 응답.redirect
        응답.redirect ('/list');
      } catch (err) {
        console.log(err); // 에러 출력하기
        return 응답.status(500).send('server error occurred');
        // 500은 서버잘못으로 인한 에러라는 뜻임
      }
    }
});

forum-express : log 4+

forum-express : log 4+

pagination을 구현해보자.


pagination의 작동 방식

스크린샷 2024-03-05 오후 9 55 09

  • 한 페이지에 5개씩 글이 보이게 구현하자.
  • /list/1 : previous가 보이면 안됨, next가 보임
  • /list/2 ~ /list/마지막에서두번째페이지 : previous와 next가 둘 다 보임
  • /list/마지막페이지 : previous만 보임, next가 보이면 안됨

pagination 구현

// server.js

// /list 페이지 : 글 목록을 보여준다. (page 파라미터에 따라 게시물을 5개씩 보여줌)
app.get('/list/:page', async (요청, 응답) => {
  // 현재 페이지에 해당되는 5개 이하의 게시물을 postlist에 저장
  let postlist = await db.collection('post').find().skip((요청.params.page-1) * 5).limit(5).toArray();
  let allPostlist = await db.collection('post').find().toArray();
  console.log(postlist, Number(allPostlist.length));

  응답.render('list.ejs', {글목록 : postlist, 페이지 : 요청.params.page, 글수 : allPostlist.length});
});
<!-- /views/list.ejs -->

    <!--페이지네이션 페이지바-->
    <div style="display:flex; justify-content:center; align-items:center;">
        <nav aria-label="pagination navigator">
            <ul class="pagination">
            <% if (Number(페이지) !== 1) { %>
                <li class="page-item"><a class="page-link" href="/list/<%= Number(페이지)-1 %>">Previous</a></li>
            <% } %>
            <li class="page-item"><a class="page-link"><%= 페이지 %></a></li>
            <% if (페이지*5 < 글수) { %>
                <li class="page-item" id="nextpage"><a class="page-link" href="/list/<%= Number(페이지)+1 %>">Next</a></li>
            <% } %>
            </ul>
        </nav>
    </div>

forum-express : log 4

forum-express : log 4

글 수정 기능과 삭제 기능을 구현해보자. 이때 method-override와 ajax-fetch를 사용하여 PUT/DELETE 요청을 구현한다.


RESTful한 API를 만들기 위한 method-override & 글 수정 기능 구현

  • form 태그에서 method 속성은 일반적으로 GET/POST만 사용 가능
  • npm에서 method-override를 다운로드 받아 method를 POST로 유지한 채 url parameter를 통해 PUT으로 요청할 수 있게끔 하자.
  • document의 고유 id를 input에 숨겨 PUT요청 시에 데이터를 전송할 수 있도록 하자.
<!-- edit.ejs -->
...

<!--메소드 오버라이딩을 통해 post요청을 put으로 바꿈-->
    <form action="/edit?_method=PUT" method="POST" class="form-box"> 
        <h4>글 수정</h4>

        <!--유저가 id 보내주기-->
        <input id="id" name="id" value="<%= 글._id %>" style="display:none">
        
        <input id="writetitle" name="title" value="<%= 글.title %>">
        <input id="writecontent" name="content" value="<%= 글.content %>">
        <input type="hidden" name="_method" value="PUT"/>
        <button type="submit">수정하기</button>
    </form> 
// server.js
app.get('/edit', async(요청, 응답) => {
    let posting = await db.collection('post').findOne({_id : new ObjectId(요청.query.id)});
    console.log(요청.query.id); 
    
    응답.render('edit.ejs', { : posting});
});

// 서버에 없는 정보일 때 대처 : 유저에게 보내라고 하거나 or db에서 읽거나
app.put('/edit', async(요청, 응답) => {
  console.log (요청.body);
  try {
    if (요청.body.title == '' || 요청.body.content == '') {
      응답.send("<script>alert('제목이나 내용이 존재하지 않습니다.');</script>");
    } 
    else {
      await db.collection('post').updateOne({_id : new ObjectId(요청.body.id) }, {$set : {title : 요청.body.title, content : 요청.body.content}});
      응답.redirect('/list');
    }
  } catch (err) {
    응답.status(500).send('server error occurred');
  }
});

ajax-fetch를 이용해 DELETE & 글 삭제 기능 구현

시나리오

  • /detail?id=~~~에 있는 삭제 버튼을 누른다
  • 서버는 그 글이 db에 있는지를 확인한다
    • 없다 -> /list로 복귀
    • 있다 -> 삭제

  • ajax를 쓰는 이유 : a태그나 form태그로 GET/POST/PUT을 하면 새로고침이 되는데, 이게 싫을 때
  • detail.ejs 안에 script 태그 안을 삭제 버튼 fetch 함수로 채운 후에 method를 DELETE로 하여 요청하자
<!-- detail.ejs -->
 <button type="button" class="btn btn-outline-danger" id="delete">삭제하기</button>
        
        <!--부트스트랩-->
        <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous">
        </script>
        

        <script>
            // btn이라는 클래스 안에 btn-outline-danger라는 클래스를 가진 요소들 중 첫번째 요소가 만약 클릭이 되었을 경우 함수에 있는걸 실행해라
            document.querySelectorAll('#delete')[0].addEventListener('click', () => {
                // 여기에 ajax 문법
                // fetch(URL) : 서버로 URL로 요청 날려줌 (이때 새로고침 없이 요청해줌)
                // method에 get인지 post인지 put인지 delete인지 설정 가능
                fetch('/delete?id=' + '<%= 글._id %>', {
                    method : 'DELETE'
                })
            });
        </script>
...
// server.js

app.delete('/delete', async(요청, 응답) => {
  let posting = await db.collection('post').findOne({_id : new ObjectId(요청.query.id)});

  console.log(posting)

  if (posting != null) {
    const confirmDelete = true;

    if (confirmDelete == true) {
      await db.collection('post').deleteOne({_id : new ObjectId(요청.query.id)});
      응답.send("<script>alert('삭제되었습니다.');</script>");
    }

    else {
      응답.redirect('/detail/' + 요청.query.id);
    }
  }

  else {
    응답.send("<script>alert('해당하는 게시물이 없습니다.'); window.location.replace('/list');</script>");
  }
});

forum-express : log 5_1

forum-express : log 5_1

회원가입 및 로그인 기능을 구현한 코드 가이드라인을 정리한다.


로그인

// /login 페이지에 사용할 DB 탐색 함수 (passport)
// 사용 방식 : passport.authenticate('local')(~~~~~~~~)
passport.use(new LocalStrategy(async (입력아이디, 입력비밀번호, cb) => {
  try {
    let result = await db.collection('user').findOne({ username : 입력아이디});

    if (!result) {
      return cb(null, false, { message: 'DB에 account가 없음' });
    }

    // 해싱된 비밀번호와 입력한 비밀번호를 비교
    let isPassword = await bcrypt.compare(입력비밀번호, result.password);
    console.log(isPassword);

    if (isPassword) {
      return cb(null, result);
    } 
    
    else {
      return cb(null, false, { message: '비밀번호 불일치' });
  } } catch (err) {
    return 응답.status(500).send('DB error occurred');
  }
}));

// login 완료 후 session 발행
// 요청.logIn 사용할 때 자동 실행된다
// done 안에 두번째 인자 : session document, 쿠키에 담아서 유저에게 보내줌
passport.serializeUser((user, done) => {
  process.nextTick(() => {
    done(null, { id: user._id, username: user.username });
  });
});

// deserializeUser : 유저가 보낸 쿠키 분석 & session과 비교 (요청.user == 유저의 정보)
// 회원가입과 로그인 페이지 API를 맨 위로 보내기
passport.deserializeUser(async(user, done) => {
  let result = await db.collection('user').findOne({_id : new ObjectId(user.id)})
  delete result.password
  process.nextTick(() => {
    return done(null, result)
  })
});

// /login : 로그인 페이지
app.get ('/login', (요청, 응답) => {
  응답.render("login.ejs", {로그인상태 : 요청.user});
});

app.post ('/login', async(요청, 응답, next)=> {
  // 제출한 아이디와 비번 쌍이 DB에 있는 건지 확인
  // -> session 생성

  // 아래 과정은 base. passport 문법으로 구현
  // const user = await db.collection('user').findOne({
  //   username : 요청.body.username,
  //   password : 요청.body.password
  // });
  // if (user == null) {
  //   console.log("이런 회원 없음");
  // }
  // else {
  //   console.log("회원가입 성공");
  // }

  passport.authenticate('local', {sessions: false}, (error, user, info) => {
    if (error) { // 서버 에러남
      return 응답.status(500).send ("server error occured");
    }

    if (!user) { // 유저가 없음 or 비밀번호 불일치
      return 응답.status(401).json (info.message);
    }

    요청.logIn(user, (err) => { // logIn함수가 session을 만들어 준다
      if (err) { // 에러나면
        return next(err);
      }

      응답.redirect("/");
    });
  })(요청, 응답, next);
});

회원가입

// /register : 회원가입
app.get ('/register', async(요청, 응답) => {
  응답.render ("register.ejs", {로그인상태 : 요청.user});
});

app.post ('/register', async(요청, 응답) => {
  if (요청.body.username == '' || 요청.body.password == '') {
    응답.send("<script>alert('아이디나 비밀번호가 작성되지 않았습니다. 다시 작성해주십시오.'); window.location.replace('/auth');</script>");
  }

  else {
    try {
      // 비밀번호를 hashing해서 저장하기
      let hashingPassword = await bcrypt.hash(요청.body.password, 10);

      await db.collection('user').insertOne({
        username : 요청.body.username, // 아이디 넣기
        password : hashingPassword, // 비밀번호 넣기 (해싱된)
        name : 요청.body.name // 이름 넣기
      });

      응답.redirect ('/');
    } catch (err) {
      console.log(err);
      return 응답.status(500).send('server error occurred');
    }
  }
});

forum-express : log 5_0

forum-express : log 5_0

개강 주간의 힘듦을 s, 다음 강의까지 남은 시간을 t, 강의시간을 M이라 할 때 다음과 같은 관계식이 성립한다.

힘듦관계식

이때 각 수업에 대한 s의 합이 10 이상이라면 카페인 수혈에 강제성이 부여된다.


주말부터 구현할 기능은 회원가입 및 로그인 및 소셜 로그인 이다. 이 로그에 회원가입과 로그인이 작동되는 원리를 작성한다.

회원가입

  • 유저가 가입을 했다 -> 아이디/비번을 DB에 저장
  • 로그인을 할 시에
    • 유저가 로그인할 때 입력한 아이디와 비밀번호랑 DB에 있는 아이디와 비밀번호가 서로 일치한다 -> 로그인 성공
    • 일치하지 않는다 -> 로그인 실패
      • 만약에 5번 일치하지 않는다 -> CAPTCHA
  • 로그인을 해야 접근할 수 있는 기능
    • 수정
    • 삭제

어떻게 접근을 가능하게 해줄까

  • session
    • 유저가 로그인에 성공했다 -> DB에 {유저아이디, 로그인날짜, 유효기간, session id}같은 걸 저장한다
    • 유저가 특정 기능에 접근한다 -> 서버에게 session id를 보낸다 -> 대조
    • 단점 : DB에 입력/출력하는 속도가 빨라야 로드시간이 줄어들 것임 (DB에 무리감)
  • JWT
    • 유저가 로그인에 성공했다 -> 유저에게 {유저아이디, 로그인날짜, 유효기간}을 암호화한 문자열을 보낸다
    • 유저가 특정 기능에 접근한다 -> 암호화한 문자열을 대조

쿠키

  • 유저가 특정 기능에 접근할 때 무언가를 보내야 하지 않을까? 그 무언가가 쿠키에 있다.
  • 브라우저는 쿠키 저장소가 있고, 쿠키 저장소에 저장해놓은 쿠키는 GET/POST시에 자동으로 전송된다.

소셜 로그인

  • 소셜 로그인은 이미 회원가입한 특정 사이트에서 저장해놓았던 정보를 끌어다가 회원가입 및 로그인하는 것
  • OAuth를 사용한다.
    OAuth 2.0

forum-express : log 2+

forum-express : log 2+

서버와 유저가 소통하는 방법인 api, rest-api를 알아보자


API

유저가 서버에게 무언가를 요청하려면 url 그리고 method가 필요하다. url은 페이지를 의미하며, method는 서버에게 하고 싶은 동작을 의미한다.

  • app.get : 서버에게 데이터를 입력하는 것을 요청 / 열람하는 것을 요청
  • app.post : 서버에게 데이터를 보내는 것을 요청 (<form>)
  • app.put/update : 서버에게 데이터를 수정하는 것을 요청
  • app.delete : 서버에게 데이터를 삭제하는 것을 요청

express가 이 method가 아주 직관적이기 때문에 매우 쉽게 서버를 구현할 수 있음.

API : method를 잘 구현해놓은 일종의 설명서


REST-API

: API를 유저 친화적으로 어떻게 작성해야 하는가 (API를 예쁘게 만들어서 url을 보더라도 이게 뭐하는 페이지인지 알 수 있게끔 하자라는 취지에서 만듦)

1) uniform interface : 일관성 있는 url + 하나의 url에 하나의 데이터
2) client-server : 유저에게 db를 조작하게 하지 말것
3) stateless : 요청끼리 서로 의존성이 있으면 안됨
4) cacheability : 요청은 캐싱이 가능해야 함 
...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.