여러 가지 방식의 동적페이지

JaeGu Jeong·2024년 2월 7일
0

CS

목록 보기
1/2

동적 페이지

동적으로 사용자에게 제공되는 페이지.

사용이유

로그인하면 회원정보에 따라 프로필 페이지가 다르다.
서버가 회원별로 HTML파일을 가지고 있다면 회원이 많은 거대한 사이트는
저장용량이 남아나질 않는다. 그래서 서버는 프로그램으로 해당 페이지 양식에
회원정보만 수정해서 새로운 페이지로 만들어 제공한다.

CGI

가장 기본적인 동적 페이지 만드는 방법이다. HTTP response의 Content-type과
payload를 프로그램으로 출력하는 방법이다. 다음 파이선 코드는 로그인한 상황이라
가정하고 JWT토큰을 "user_id=123, nickname=jeong"이라고 설정한 후 웹서버가
fork하면서 환경변수로 넘겨준 JWT를 파이선으로 파싱해서 HTML양식을 만들어주는 스크립트.

#!/usr/bin/env python
import os
from http.cookies import SimpleCookie
import jwt

# 복호화 할 시크릿 키도 환경변수에서 읽기.
SECRET_KEY = os.environ.get('JWT_SECRET_KEY', 'default_secret_key')

# JWT 디코딩 함수
def decode_jwt(cookie_value):
    decoded_token = jwt.decode(cookie_value, SECRET_KEY, algorithms=['HS256'])
    return decoded_token

# HTTP_COOKIE 환경 변수에서 쿠키 값을 읽기.
cookie_string = os.environ.get('HTTP_COOKIE', '')
cookie = SimpleCookie(cookie_string)

# 'cookie' 쿠키가 있는지 확인합니다.
if 'cookie' in cookie:
    # JWT 디코딩하여 유저 아이디와 닉네임을 얻기.
    cookie_value = cookie['cookie'].value
    decoded_token = decode_jwt(cookie_value)

    if decoded_token:
        user_id = decoded_token.get('user_id', '')
        nickname = decoded_token.get('nickname', '')

        # HTML 양식으로 출력합니다.
        print("Content-type: text/html\n")
        print(f'<h1>Hello, {nickname} ({user_id})!</h1>')
        exit()

출력만 양식을 맞춰주면 언어의 제약은 특별히 없다.

print("Content-type: text/html\n")
print(f'<h1>Hello, {nickname} ({user_id})!</h1>')

만들어진 웹 페이지 HTML코드

<h1>Hello, jeong (123)!</h1>

Servlet

JSP와 Spring에서 사용하는 기술.
Java기반 WAS에서 실행되는 Java클래스.

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/profile")
public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // HTTP 헤더에서 'Authorization' 값을 읽기.
        String authorizationHeader = request.getHeader("Authorization");

        if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
            // 'Bearer ' 부분을 제외한 토큰 값을 추출.
            String jwtToken = authorizationHeader.substring(7);

            // JWT 디코딩하여 닉네임과 유저 아이디를 얻기.
            Claims claims = Jwts.parser().setSigningKey("JWT_SECRET_KEY").parseClaimsJws(jwtToken).getBody();
            String user_id = claims.get("user_id", String.class);
            String nickname = claims.get("nickname", String.class);

            // HTML 양식으로 출력.
            response.setContentType("text/html");
            try (PrintWriter out = response.getWriter()) {
                out.println("<h1>Hello, " + nickname + " (" + user_id + ")!</h1>");
            }
        } else {
            // 인증 실패 페이지.
        }
    }
}

동작 비교

동적 페이지를 제공한다는 같은 목적을 가지고 있지만 방식은 다르다.
CGI는 실행할 때마다 fork를 하고 출력이 끝나면 자식 프로세스는 종료하하고
servlet은 servlet container를 통해서 페이지를 제작하는데, 요청이 들어오면
컨테이너가 servlet 객체를 생성하고 스레드를 생성해서 처리한다.
프로세스를 생성하는 방식보다 오버헤드가 작다. 반면 항시 servlet container를
실행하고 있어야 하기 때문에 서버자원이 CGI 방식보다 더 요구될 수 있다.

Frontend Frameworks

요즘은 RESTful API와 SPA 조합으로 동적 인터페이스를 개발한다. 서버가
데이터 작업 후 양식 만들고 빈칸 채워서 넘기면 브라우저의 js엔진으로 꾸미던 방식에서
브라우저가 js로 양식 만들고 필요한 빈칸 데이터만 서버에게 받아서 채우기로 변경되었다.
서버는 데이터 작업에만 집중 할 수 있도록 역할이 분리 되었다.

import React, { useState, useEffect } from 'react';
import axios from 'axios';

const ProfilePage = () => {
  const [userNickname, setUserNickname] = useState('');
  const [userUserId, setUserUserId] = useState('');

  useEffect(() => {
    // axios로 데이터 불러오기.
    const fetchData = async () => {
      try {
        // 예시 URL, 실제로는 사용할 API의 엔드포인트를 지정.
        const response = await axios.get('https://example.com/api/user-info');

        // 받아온 데이터에서 닉네임과 유저 아이디를 추출하여 상태에 설정.
        setUserNickname(response.data.nickname);
        setUserUserId(response.data.userId);
      } catch (error) {
        console.error('Error fetching data:', error);
      }
    };
    fetchData();
  }, []);

  return (
    <div>
      {/* 상태에 저장된 닉네임과 유저 아이디를 사용하여 UI를 렌더링. */}
      <h1>Hello, {userNickname} ({userUserId})!</h1>
    </div>
  );
};

export default ProfilePage;

페이지 제작을 온전히 서버에서 하던 이전 방식과 다르게 클라이언트의 자원으로
Javascript 엔진을 돌려서 페이지를 제작한다. 복잡한 웹 프로젝트라도 분업 및 협업하기
쉽도록 발전되고 있다.

profile
BackEnd Developer

0개의 댓글