본문 바로가기
TIL

[231006] HTTP 공부, 방명록 기능 검토

by 진진리 2023. 10. 6.
728x90

HTTP 알아보기

  • HTTP(Hypertext Transfer Protocol)
    • 서버/클라이어트 모델을 따르는 프로토콜(기본 포트 80)
    • TCP/IP 위에서 작동
    • 모든 종류의 데이터 전송 가능

Connectionless 방식: 서버에 연결하고 요청해서 응답을 받으면 연결을 끊음

-> stateless: 클라이언트의 이전 상태 정보를 알 수 없음 - cookie를 이용해 이 문제를 해결

 

Cookie: 클라이언트아 서버의 상태 정보를 담고 있는 정보조각

서버 - 클라이언트 로그인 정보 등을 cookie를 키로하여 자신의 DB에 저장 후 cookie를 클라이언트에게 보냄

클라이언트 - 다음 요청 시 cookie를 서버에 보냄으로써 서버가 cookie 값으로 db를 조회하여 로그인 여부 등 확인

 

  • URI - 자원의 위치를 알려주기 위한 프로토콜. "프로토콜+위치+자원명"으로 자원에 접근
  • HTTP - 전송 프로토콜

 

  • Method(메서드)
    • GET, POST, PUT, DELETE, HEAD: 어제 공부
    • OPTIONS: 웹서버가 지원하는 메서드의 종류를 요청
    • TRACE: 클라이언트의 요청을 그대로 반환(echo) - 서버 상태를 확인하기 위한 목적
    • Restful API 서버의 경우 명시적으로 메서드를 구분

 

  • 요청데이터(HTTP request) 포맷: 요청 메서드 + 요청 URI(도메인->ip 변환) + HTTP 버전
    • + 그 외 Host, Content-Type, Cookie, User-Agent
  • 응답헤더(HTTP Response) 포맷: 프로토콜과 응답코드 + 날짜 + 서버 프로그램 및 스크립트 정보
    • + 그 외 마지막 수정일, 캐쉬 제어 방식, 콘텐츠 길이 및 타입
  • 응답 코드: 2XX 성공, 4XX 요청 오류, 5XX 서버 오류

 

  • Keep Alive: HTTP 1.1부터 지원하는 기능.

하나의 연결에 하나의 요청을 하는 것을 기준으로 설계되었으나 비효율적임

-> Keep-alive 설정을 하면, 지정된 시간 동안 연결을 끊지 않고 요청을 계속해서 보낼 수 있음

Connection: Keep-Alive 

Keep-Alive:timeout=5, max=200 (하나의 연결당 5초 유지, 연결 최대 200개까지 허용)

 


HTTPS

SSL: 데이터 보안을 위해 개발한 통신 레이어. 표현 계층의 프로토콜로 데이터를 암호화

HTTPS: SSL 레이어 위에 HTTP를 통과 시킴으로써 HTTP 문서를 암호화 및 복호화 할 수 있음

HTTP는 평문 데이터를 기반으로 하기 때문에 민감한 정보가 인터넷 상에 노출됨

 

  • HTTP와의 차이
    • "https://"로 시작. 기본 포트번호 443
    • 인증서를 이용해 접속 사이트를 신뢰 가능한지 평가 가능
    • HTTP에 비해 느림

  • 팀원이 구현한 방명록 기능 검토하기(1)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>방명록</title>
    
    //firebase, css파일, jquery, 부트스트랩 import 부분

    <script type="module">
       //... DB 연결 

    	//방명록 불러오는 부분
		const dbRef = database.ref('logs');
		dbRef.on("value", (snapshot) => {
   			snapshot.forEach((child) => {

        		const object = child.val();
        		let temp = `
  		  	<div class="log">
    		    <div class="input-group mb-3">
   		         	<span class="input-group-text">${object.date}</span>
 		           	<span class="input-group-text">${object.name}</span>
    		        <span><input type="text" id="deleteLogPw" placeholder="Password" aria-label="Password" class="form-control"></span>
    		        <button class="btn btn-secondary" type="button" id="deleteLogBtn">삭제</button>
   		         	<div class="logText" id = ${child.ref.key}>
      		          ${object.content}
    		        </div>
    		    </div>
  		  </div>
 		   `
      		  $('#logBox').append(temp)

		    });
		});
		//방명록 불러오는 부분 끝남

        //방명록 등록하는 부분
        $(document).on("click", "#logPushBtn", function () {

            let name = $('#logName').val();
            let pw = $('#logPassword').val();
            let content = $('#logContent').val();
            const today = new Date();
            let day = today.getDate();
            let month = today.getMonth() + 1;
            let year = today.getFullYear();

            let date = `${year}-${month}-${day}`;

            let doc = {
                'name': name,
                'pw': pw,
                'content': content,
                'date': date
            }

            await database.ref('logs').push(doc);

            window.location.reload();
        });
        //방명록 등록 끝



        //방명록 삭제하는 부분
        $(document).on("click", "#deleteLogBtn", function () {

            //alert("click");

            let parentDiv = $(this).closest('div');
            let textDiv = parentDiv.children('.logText');
            let pwInput = parentDiv.find('input');


            let id = textDiv.attr('id');
            let password = pwInput.val();

            const dbRef = database.ref('logs');

            dbRef.on("value", (snapshot) => {
                snapshot.forEach((child) => {
                    const object = child.val();

                    if (id == child.ref.key) {
                        if (object.pw == password) {
                            dbRef.child(id).remove();
                        }
                        else {
                            alert("잘못된 비밀번호");

                        }
                    }
                });
            });
            window.location.reload();
        });
        //방명록 삭제 끝남
    </script>
</head>


<body>
    <div class="box1" style="position:relative;">
        <div class="uppertext" style="position: absolute;">
            //위 텍스트
        </div>
        <div class="box2">
            //왼쪽 박스
        </div>
        <div class="rings" style="position: absolute;">
            // 링
        </div>
        
        //--------------------------- 방명록 구현 ---------------------------
        <div class="box3">
            <div class="inputlogBox">
                <div class="input-group">
                    <span class="input-group-text">Name</span>
                    <input type="text" id="logName" placeholder="Name" aria-label="Name" class="form-control">
                    <span class="input-group-text">Password</span>
                    <input type="text" id="logPassword" placeholder="Password" aria-label="Password"
                        class="form-control">
                </div>

                <textarea class="form-control" id="logContent" rows="3"></textarea>

                <div>
                    <button type="button" id="logRegisterBtn" class="btn btn-secondary" style="float:right">등록</button>
                </div>

            </div>
            <div class="logBox">
                <div class="log" id="logBox">

                </div>
            </div>
        </div>
        // ---------------------------------------
        <div class="buttons" style="position: absolute;">
            //버튼
        </div>
    </div>

    <script src="../IntroTeam/db/buttonfunc.js"></script>
</body>

</html>
  • firebase 실시간 데이터베이스 설정
 
<script type="module">
        const firebaseConfig = {
           ...
        };

        firebase.initializeApp(firebaseConfig);
        const database = firebase.database();

 

  • 방명록 불러오기
const dbRef = database.ref('logs');
        dbRef.on("value", (snapshot) => {
            snapshot.forEach((child) => {

database.ref('logs')로 logs에 접근

가져온 데이터 snapshot

snapshot.forEach(child)로 각 데이터 child에 접근

const object = child.val();
${object.date}
${object.name}
${object.content}

다음과 같이 방명록 내용 가져오기

        <div class="logText" id = ${child.ref.key}>
                ${object.content}
            </div>

불러오면서 해당 부분의 id를 child.ref.key로 설정

 

 

  • 방명록 등록하기

방명록 이름, 비밀번호, 내용을 입력 후 버튼 클릭 후 아래의 함수 실행

$(document).on("click", "#logPushBtn", function () {

날짜는 Date()의 년,월, 일을 따로 저장 후 합침

            const today = new Date();
            let day = today.getDate();
            let month = today.getMonth() + 1;
            let year = today.getFullYear();

            let date = `${year}-${month}-${day}`;

DB에 저장할 데이터 doc 저장

let doc = {
                'name': name,
                'pw': pw,
                'content': content,
                'date': date
            }

데이터베이스에 push 후 새로고침

await database.ref('logs').push(doc);
window.location.reload();

 

 

  • 방명록 삭제하기

삭제하기 버튼을 누르면 다음 함수 실행

$(document).on("click", "#deleteLogBtn", function () ...

가장 가까운 div인 parentDiv의 내용이 textDiv, 삭제할 때 입력한 비밀번호를 input에 저장

let parentDiv = $(this).closest('div');
            let textDiv = parentDiv.children('.logText');
            let pwInput = parentDiv.find('input');

방명록을 불러올 때 저장했던 id를 id에 저장, 입력받은 비밀번호를 passoword에 저장

let id = textDiv.attr('id');
let password = pwInput.val();

데이터베이스에 id, password와 일치하는 내용을 삭제

const dbRef = database.ref('logs');

            dbRef.on("value", (snapshot) => {
                snapshot.forEach((child) => {
                    const object = child.val();

                    if (id == child.ref.key) {
                        if (object.pw == password) {
                            dbRef.child(id).remove();
                        }
                        else {
                            alert("잘못된 비밀번호");

                        }
                    }
                });
            });

 

------메인 페이지와 방명록 연동되는  부분은 다음에 리뷰------


파일 분리 및 연결

  • 코드 길이를 줄여 한 눈에 보기 쉽도록 .css 파일 분리하기

같은 폴더 내의 css 폴더 생성

http 파일 내의 <style> ... </style> 내용을 .css 파일로 따로 저장

기존 http 파일에서 다음과 같이 연결해줌

<link href="./css/index.css" rel="stylesheet" type="text/css" />

 

  • 공통 기능인 버튼 이동 기능을 .js 파일로 분리하기

팀원 페이지에 공통으로 들어가는 <script> ... </script> 내부 내용을 buttonfuc.js파일로 분리

해당 기능이 포함되는 .html 파일의 <body>태그 안 마지막 부분에 <script src="../IntroTeam/db/buttonfuc.js"> </script>를 붙이기

<script src="../IntroTeam/db/buttonfunc.js"></script>

외부 파일에서 <script type="module">과 같이 작성하는 경우 모듈은 로컬 서버에서는 작동하지 않음

 

+++ js를 분리시킬 때 데이터베이스를 import하는 부분까지 다 분리시킨 것이 안되는 원인. js를 분리시키면 로컬에서 값을 찾는데 데이터베이스는 https 프로토콜로 import되기 때문에 로컬에서 결국 못찾게 되어서 오류가 발생

 

  • firebase 실시간 데이터베이스를 사용하는 js파일 분리하기

위의 코드를 위에 삽입함

 

+++ .js파일을 분리함으로써 firestore db와 realtime db를 모두 사용하는 것이 가능해졌다고 함