WeniVooks

검색

웹/네트워크/HTTP 베이스캠프

서버 상태 저장

9.2.1 세션(Session)

세션은 서버 측에서 클라이언트의 상태를 유지하는 방법입니다. 좀 더 쉽게 표현하면 세션은 서버 내에 남아 있는 사용자 연결 정보입니다. 일반적으로 서버의 메모리나 데이터베이스에 저장되며, 클라이언트에게는 세션 ID만 전달됩니다. 클라이언트는 세션 ID를 쿠키에 저장하고, 이후 서버에 요청을 보낼 때마다 세션 ID를 함께 전송합니다.

Python에서 세션을 사용하는 예제 코드

import uuid
from http.server import HTTPServer, SimpleHTTPRequestHandler
from urllib.parse import parse_qs
 
sessions = {}  # 세션 데이터를 저장할 딕셔너리
 
class SessionHandler(SimpleHTTPRequestHandler):
    def do_GET(self):
        print(sessions)
        session_id = self.get_session_id()
        if session_id not in sessions:
            sessions[session_id] = {"username": None}
 
        if self.path == "/":
            self.send_response(200)
            self.send_header("Content-type", "text/html")
            if session_id not in self.headers.get("Cookie", ""):
                self.send_header("Set-Cookie", f"sessionid={session_id}")
            self.end_headers()
            self.wfile.write(b"<html><body>")
            if sessions[session_id]["username"]:
                self.wfile.write(
                    f"<h1>Welcome, {sessions[session_id]['username']}!</h1>".encode()
                )
            else:
                self.wfile.write(b'<form method="post" action="/login">')
                self.wfile.write(b'<input type="text" name="username">')
                self.wfile.write(b'<input type="submit" value="Login">')
                self.wfile.write(b"</form>")
            self.wfile.write(b"</body></html>")
        else:
            self.send_error(404)
 
    def do_POST(self):
        if self.path == "/login":
            content_length = int(self.headers["Content-Length"])
            post_data = self.rfile.read(content_length).decode("utf-8")
            username = parse_qs(post_data)["username"][0]
            session_id = self.get_session_id()
            sessions[session_id]["username"] = username
            self.send_response(302)
            self.send_header("Location", "/")
            self.end_headers()
        else:
            self.send_error(404)
 
    def get_session_id(self):
        if "Cookie" in self.headers:
            cookie = self.headers["Cookie"]
            if "sessionid" in cookie:
                return cookie.split("sessionid=")[1].split(";")[0]
        session_id = str(uuid.uuid4())
        return session_id
 
def run(server_class=HTTPServer, handler_class=SessionHandler, port=8000):
    server_address = ("", port)
    httpd = server_class(server_address, handler_class)
    print(f"Starting server on port {port}...")
    httpd.serve_forever()  # 서버 시작
 
if __name__ == "__main__":
    run()  # 직접 실행될 경우 서버 시작
 
import uuid
from http.server import HTTPServer, SimpleHTTPRequestHandler
from urllib.parse import parse_qs
 
sessions = {}  # 세션 데이터를 저장할 딕셔너리
 
class SessionHandler(SimpleHTTPRequestHandler):
    def do_GET(self):
        print(sessions)
        session_id = self.get_session_id()
        if session_id not in sessions:
            sessions[session_id] = {"username": None}
 
        if self.path == "/":
            self.send_response(200)
            self.send_header("Content-type", "text/html")
            if session_id not in self.headers.get("Cookie", ""):
                self.send_header("Set-Cookie", f"sessionid={session_id}")
            self.end_headers()
            self.wfile.write(b"<html><body>")
            if sessions[session_id]["username"]:
                self.wfile.write(
                    f"<h1>Welcome, {sessions[session_id]['username']}!</h1>".encode()
                )
            else:
                self.wfile.write(b'<form method="post" action="/login">')
                self.wfile.write(b'<input type="text" name="username">')
                self.wfile.write(b'<input type="submit" value="Login">')
                self.wfile.write(b"</form>")
            self.wfile.write(b"</body></html>")
        else:
            self.send_error(404)
 
    def do_POST(self):
        if self.path == "/login":
            content_length = int(self.headers["Content-Length"])
            post_data = self.rfile.read(content_length).decode("utf-8")
            username = parse_qs(post_data)["username"][0]
            session_id = self.get_session_id()
            sessions[session_id]["username"] = username
            self.send_response(302)
            self.send_header("Location", "/")
            self.end_headers()
        else:
            self.send_error(404)
 
    def get_session_id(self):
        if "Cookie" in self.headers:
            cookie = self.headers["Cookie"]
            if "sessionid" in cookie:
                return cookie.split("sessionid=")[1].split(";")[0]
        session_id = str(uuid.uuid4())
        return session_id
 
def run(server_class=HTTPServer, handler_class=SessionHandler, port=8000):
    server_address = ("", port)
    httpd = server_class(server_address, handler_class)
    print(f"Starting server on port {port}...")
    httpd.serve_forever()  # 서버 시작
 
if __name__ == "__main__":
    run()  # 직접 실행될 경우 서버 시작
 
  • 로그인
  • 로그인 후 세션 확인
  • 세션 지워보기
  • Network에 Request Header보기

클라이언트 측의 쿠키와 로컬 스토리지, 그리고 서버 측의 세션을 적절히 사용하면 웹 애플리케이션에서 상태를 유지하고 관리할 수 있습니다. 각 방법의 특성과 보안 고려사항을 이해하고, 애플리케이션의 요구사항에 맞게 선택하는 것이 중요합니다.

9.1 클라이언트 상태 저장10장 HTTPS