본문 바로가기

23년 2학기 학교공부/컴퓨터네트워크

[CN] Client-side 동적 웹페이지 배포해보기

목차

    728x90
    반응형
    SMALL
    // http_server/dir/statics/myscript.js
    
    const myInterval = setInterval(myTimer, 1000);
    
    function myTimer() {
      const date = new Date();
      document.getElementById('timer').innerHTML = '현재 시간: ' + date.toLocaleTimeString() + '<br><button onclick="myTimerStop()">Stop time</button><br>';
    }
    
    function myTimerStop() {
      clearInterval(myInterval);
    }
    <!-- http_server/dir/index.html -->
    
    <!DOCTYPE html>
    <html>
    <body>
    
    <h1>index.html</h1>
    
    <p>총 방문자: {{ COUNTER }}</p>
    
    <div id="timer">
    </div>
    
    </body>
    <script src="statics/myscript.js"></script>
    </html>

     

    # http_server/http_server.py
    
    import os
    import http
    import http.server
    import socketserver
    import sqlite3
    
    
    PREFIX = '/counter'
    
    FLAGS = _ = None
    DEBUG = False
    
    EXT = {'.html': 'text/html;charset=utf-8',
           '.js': 'text/javascript;charset=utf-8'}
    
    CONN = sqlite3.connect('./Log.db')
    CUR = CONN.cursor()
    CUR.execute('''CREATE TABLE IF NOT EXISTS Log (
                     id INTEGER PRIMARY KEY AUTOINCREMENT,
                     ip TEXT,
                     request TEXT);''')
    CONN.commit()
    
    
    class MyHTTPDaemon(http.server.HTTPServer):
        allow_reuse_address = True
    
    
    class MyHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
        def __init__(self, *args, **kwargs):
            self.rootdir = FLAGS.rootdir
            self.conn = CONN
            self.cur = CUR
            super().__init__(*args, **kwargs)
    
        def do_GET(self):
            if DEBUG:
                print(f'Command: {self.command}')
                print(f'Path: {self.path}')
                print(f'Headers: {self.headers}')
    
            self.cur.execute('''INSERT INTO Log (ip, request)
                                VALUES (?, ?);''', (self.client_address[0], self.requestline))
            self.conn.commit()
    
            if not self.path.startswith(PREFIX):
                return None
            self.path = self.path[len(PREFIX):]
            if self.path == '/':
                path = 'index.html'
            else:
                path = self.path[1:]
            path = os.path.join(self.rootdir, path)
            if DEBUG:
                print(f'Joined path: {self.rootdir} {self.path} {path}')
            if not os.path.exists(path):
                self.send_error(http.HTTPStatus.NOT_FOUND, 'File not found')
            else:
                ext = os.path.splitext(path)[-1].lower()
                self.send_response(http.HTTPStatus.OK)
                self.send_header('Content-Type', EXT[ext])
                with open(path, 'rb') as f:
                    self.cur.execute('''SELECT MAX(id) FROM Log;''')
                    counter = self.cur.fetchone()[0]
                    body = f.read()
                    body = body.replace('{{ COUNTER }}'.encode('utf-8'), f'{counter}'.encode('utf-8'))
                    self.send_header('Content-Length', len(body))
                    self.end_headers()
                    self.wfile.write(body)
    
    def main():
        print(f'Parsed arguments: {FLAGS}')
        print(f'Unparsed arguments: {_}')
    
        with MyHTTPDaemon((FLAGS.host, FLAGS.port), 
                          MyHTTPRequestHandler) as httpd:
            try:
                print(f'Start server {httpd.server_address}')
                httpd.serve_forever()
            except KeyboardInterrupt:
                print(f'Stop server {httpd.server_address}')
                httpd.shutdown()
    
    
    if __name__ == '__main__':
        import argparse
    
        parser = argparse.ArgumentParser()
        parser.add_argument('--debug', action='store_true',
                            help='Debug message')
        parser.add_argument('--host', default='0.0.0.0', type=str,
                            help='IP address')
        parser.add_argument('--port', default=8888, type=int,
                            help='Port number')
        parser.add_argument('--rootdir', default='./dir', type=str,
                            help='Root directory')
    
        FLAGS, _ = parser.parse_known_args()
        DEBUG = FLAGS.debug
    
        main()

     

     

     

     

    만약 http_server.py에 PREFIX를 추가하지 않으면,

     

     

     

    -- 실습 --

     

    <!-- mybp/templates/index.html -->
    
    <!DOCTYPE html>
    <html>
    
    <title>My Paste Bin - Main</title>
    
    <link rel="stylesheet" href="{{ url_for('mybp.static', filename='maincss.css') }}">
    
    <body>
    
    <h1>Pastes ( {{ count_pastes }} pastes from {{ count_users }} users )</h1>
    
    <div id='pastes'>
    </div>
    
    
    </body>
    
    <script src="{{ url_for('mybp.static', filename='mainjs.js') }}"></script>
    
    </html>

     

    // mybp/static/mainjs.js
    
    async function fetchRequestWithError() {
        try {
          const url = `http://localhost:8080/pastebin/api/pastes/`;
          const response = await fetch(url);
          if (response.status >= 200 && response.status < 400) {
            const data = await response.json();
            for (var key in data) {
              ndiv = document.createElement('div');
              ndiv.innerHTML = `<h3> ${data[key]['title']} </h3><p> ${data[key]['content']}</p><hr>`;
              pdiv = document.getElementById('pastes');
              pdiv.appendChild(ndiv);
            }
          } else {
            console.log(`${response.statusText}: ${response.status} error`);
          }
        } catch (error) {
          console.log(error);
        }
      }
      
      fetchint = setInterval(fetchRequestWithError, 10*1000);

     

     

    uvicorn 서버 실행

     

    flask 서버 실행

     

     

    지금은 일정 시간마다 paste들이 계속해서 출력되고 있다.

     

    최대 10개까지 출력하되, 최근 글이 가장 위로 오게 해보자.

     

     

    -- 과제 --

     

    // mybp/static/mainjs.js
    
    let pasteCount = 0;
    
    async function fetchRequestWithError() {
      try {
        const url = `http://localhost:8080/pastebin/api/pastes/`;
        const response = await fetch(url);
        if (response.status >= 200 && response.status < 400) {
          const data = await response.json();
          for (var key in data) {
            // 현재 렌더링하고자 하는 paste는 key+1번째 paste이다.
            // 지금까지 렌더링 된 paste의 개수는 pasteCount.
            // pasteCount번째 paste들은 중복되어 출력하지 않고 continue로 넘어간다.
            if (key < pasteCount) {
              continue;
            }
    
            pasteCount += 1;
            ndiv = document.createElement('div');
            ndiv.innerHTML = `<h3>${data[key]['title']} </h3><p> ${data[key]['content']}</p><hr>`;
            pdiv = document.getElementById('pastes');
            // appendChild 및 append는 요소 맨 마지막에 넣는 함수이므로,
            // 요소 맨 앞에 추가하는 prepend 함수를 사용한다.
            pdiv.prepend(ndiv);
    
            // 현재까지 렌더링 된 paste의 수가 6개를 넘기면
            // 맨 아래 출력된 paste를 제거한다.
            if (pasteCount > 6) {
              pdiv.removeChild(pdiv.lastElementChild);
            }
          }
        } else {
          console.log(`${response.statusText}: ${response.status} error`);
        }
      } catch (error) {
        console.log(error);
      }
    }
    
    fetchint = setInterval(fetchRequestWithError, 10 * 1000);

     

    728x90
    반응형
    LIST