본문 바로가기

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

[CN] 서버사이드 동적 웹

목차

    728x90
    반응형
    SMALL

    pip 업그레이드로 해결

    python3 -m pip install --upgrade pip

     

     

    #app.py
    from flask import Flask, render_template
    
    app = Flask(__name__)
    
    @app.route('/hello/')
    @app.route('/hello/<name>')
    def hello(name=None):
        return render_template('hello.html', name=name)
    <!--templates/hello.html-->
    <!DOCTYPE html>
    <title>Hello from Flask!</title>
    {% if name %}
    <h1>Hello {{ name }}!</h1>
    {% else %}
    <h1>Hello, World!</h1>
    {% endif %}

     

     

    /hello로 접속시 308 상태코드와 함께 /hello/로 이동함.

     

     

     

     

     

    docker container 다 지우고 지난주 실습을 다시 진행해보자 ,,

    (마운트한 로컬 위치를 바꾸는 방법을 모르겠다.)

     

    # http_server.py
    
    import os
    import http
    import http.server
    import socketserver
    import sqlite3
    
    PREFIX = ''
    
    FLAGS = _ = None
    DEBUG = False
    
    EXT = {'.html': 'text/html;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()
    <!-- dir/index.html -->
    
    <!DOCTYPE html>
    <html>
    <body>
    
    <h1>index.html</h1>
    
    <p>총 방문자: {{ COUNTER }}</p>
    
    </body>
    </html>

     

     

     

     

     

     

    # mynginx9 컨테이너

     

    # nginx.conf
    
    user  nginx;
    worker_processes  auto;
    
    error_log  /var/log/nginx/error.log notice;
    pid        /var/run/nginx.pid;
    
    
    events {
        worker_connections  1024;
    }
    
    
    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;
    
        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';
    
        access_log  /var/log/nginx/access.log  main;
    
        sendfile        on;
    
        keepalive_timeout  65;
    
        server {
            listen       80;
            server_name  localhost;
    
            location / {
                root   /usr/share/nginx/html;
                index  index.html index.htm;
            }
    
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   /usr/share/nginx/html;
            }
            
        }
    }

     

     

    # mydb9 컨테이너

    apt update
    apt install python3.10 python3-pip python3-dev python3-venv python3-pip net-tools vim

    apt-get install -y libmariadb-dev
    pip install uvicorn fastapi sqlalchemy alembic mariadb

     

    $ mariadb -uroot -p

    pw : my-secret-pw

    $ CREATE DATABASE pastebin;

    $ CREATE USER IF NOT EXISTS pasteuser@pastebin IDENTIFIED BY 'user-secret-pw';

    $ GRANT ALL PRIVILEGES ON pastebin.* TO 'pasteuser'@'%' IDENTIFIED BY 'user-secret-pw';

    $ FLUSH PRIVILEGES;

     

    # myback9 컨테이너

    apt update
    apt install python3.10 python3-pip python3-dev python3-venv python3-pip net-tools vim

    apt-get install -y libmariadb-dev
    pip install uvicorn fastapi sqlalchemy alembic mariadb

     

     

     

     

     

    http_server.py의 PREFIX 수정

     

     

     

     

    nginx.conf에서 proxy 수정

    proxy_pass에서 ip주소 혹은 container 이름을 사용하여 설정할 수 있다. 오른쪽 nginx.conf에서 42번째 줄과 43번째 줄 둘 중 하나만 쓰여야 하며 51, 52번째 줄도 동일하다. 위 코드는 이해를 돕기 위함이다.

     

     

     

     

     

     

    # mybp 컨테이너

    apt update
    apt install python3.10 python3-pip python3-dev python3-venv python3-pip net-tools vim

    apt-get install -y libmariadb-dev
    pip install uvicorn fastapi sqlalchemy alembic mariadb Flask

     

     

     

     

    nginx.conf 설정

    Flask 접속 위한 location 추가

     

     

     

    mybp/app.py 수정

    from flask import Flask, render_template, Blueprint
    import urllib.request
    import json
    
    app = Flask(__name__)
    
    @app.route('/hello/')
    @app.route('/hello/<name>')
    def hello(name=None):
        return render_template('hello.html', name=name)
    
    endpoint = 'http://mynginx9/pastebin/api'
    
    bp = Blueprint('mybp', __name__, 
                   static_folder='static',
                   static_url_path='/pastebin/static',
                   template_folder='templates',
                   url_prefix='/pastebin')
    
    @bp.route(f'/', methods=['GET'])
    @bp.route(f'/index.html', methods=['GET'])
    def get_index():
        count_users = 0
        url = f'{endpoint}/users/'
        data = None
        headers = {'Accept': 'application/json'}
        method = 'GET'
        req = urllib.request.Request(url=url,
                                     data=data,
                                     headers=headers,
                                     method=method)
        with urllib.request.urlopen(req) as f:
            data = json.loads(f.read())
            count_users = len(data)
    
        count_pastes = 0
        url = f'{endpoint}/pastes/'
        data = None
        headers = {'Accept': 'application/json'}
        method = 'GET'
        req = urllib.request.Request(url=url,
                                     data=data,
                                     headers=headers,
                                     method=method)
        with urllib.request.urlopen(req) as f:
            data = json.loads(f.read())
            count_pastes = len(data)
    
        return render_template('index.html', 
                               count_users=count_users,
                               count_pastes=count_pastes)
    
    app.register_blueprint(bp)

    S

     

     

    app/crud.py 수정

    ...
    
    # 모든 메모 열람
    def get_pastes(db: Session, skip: int = 0, limit: int = 100):
        return db.query(models.Paste).order_by(models.Paste.id.asc()).offset(skip).limit(limit).all()

     

    app/main.py 수정

    ...
        
    # 모든 메모 열람
    @app.get('/pastes/', response_model=List[schemas.Paste])
    def get_pastes(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
        pastes = crud.get_pastes(db, skip=skip, limit=limit)
        return pastes

     

    가장 하단의 #모든 메모 열람 부분을 추가해주어야한다.

    mybp의 app.py에서 {endpoint}/users/와 {endpoint}/pastes/의 url을 urllib.request 패키지로 요청하기 때문에 해당 경로가 존재하지 않으면 urllib.error.HTTPError: HTTP Error 404: Not Found 와 같은 에러가 발생한다.

     

     

     

     

     

     

     

     

     

     

     

     

    728x90
    반응형
    LIST