shadcn ui

shadcn/ui React를 기반으로 Tailwind CSS를 활용해 빠르고 효율적으로 UI 컴포넌트를 구축할 수 있도록 돕는 오픈소스 UI 라이브러리이다. 이 라이브러리는 일반적인 UI 키트와는 다르게 컴포넌트 코드를 직접 복사해서 사용하는 방식을 채택하고 있어, 사용자 맞춤화와 확장성이 뛰어나다.

shadcn ui의 주요 특징 

1. tailwind CSS기반 

- 모든 스타일링은 Tailwind CSS유틸리티 클래스를 사용하여 작성된다. 

- 덕분에 기존 Tailwind프로젝트와의 호환성이 매우 뛰어난 편이다. 

2. 코드 우선 접근 방식 

- 일반적인 UI라이브러리처럼 외부 패키지를 설치해 사용하는 대신 , 컴포넌트를 직접 복사해서 프로젝트 내에 포함하는 방식을 권장한다. 

- 이를 통해 컴포넌트 스타일과 동작을 프로젝트 요구에 맞게 쉽게 수정할 수 있다. 

3. Radix UI활용 

- Radix UI의 접근성 높은 컴포넌트를 기반으로 빌드되었다. 

- 예를 들어, 드롭다운, 모달, 토글 등 접근성 지원이 내장된 고급 컴포넌트를 제공한다. 

4. 유연성과 확장성 

- 컴포넌트 코드를 복사하므로 완전한 제어가 가능하다. 

- 디자인 시스템의 일관성을 유지하거나 특정 기능을 커스터마이징하는 데 유리하다 

5. 간단한 설치 

- 컴포넌트를 가져오고 Tailwind 설정을 추가하기만 하면 바로 사용할 수 있다. 

shadcn/ui와 기존 UI 라이브러리의 차이점

shadcn ui 기존 UI라이브러리 
컴포넌트를 직접 복사해 사용 패키지 형태로 설치 및 사용
Tailwind CSS와 완벽히 통합 스타일링은 종종 자체 CSS나 CSS-in-JS 사용
높은 커스터마이징 및 코드 제어 가능 제한된 커스터마이징 옵션 제공
Radix UI 기반으로 접근성 지원 접근성 수준은 라이브러리에 따라 다름

공식 사이트  및 문서 

https://ui.shadcn.com/

 

shadcn/ui

Beautifully designed components that you can copy and paste into your apps. Accessible. Customizable. Open Source.

ui.shadcn.com

 

https://github.com/shadcn-ui/ui

 

GitHub - shadcn-ui/ui: Beautifully designed components that you can copy and paste into your apps. Accessible. Customizable. Ope

Beautifully designed components that you can copy and paste into your apps. Accessible. Customizable. Open Source. - shadcn-ui/ui

github.com

 

 

next.js로  프로젝트를 시작하게 되면 루트폴더에는 다양한 폴더들이 생성이된다. 그 중에서 ".next"라는 녀석에 대해서 알아보기로 했다. 

이 폴더는 Next.js프로젝트의 빌드와 실행 과정에서 생성되는 핵심 파일들을 담고 있는 디렉토리이다. 이 폴더는 캐시 역할도 수행하지만 그 외에도 여러 가지 중요한 기능을 포함하고 있다. 

.next 폴더의 역할

.next 폴더는 Next.js가 프로젝트를 최적화하고 실행하는 데 필요한 중간 파일과 최종 산출물을 저장합니다. 주요 역할은 다음과 같습니다:

캐싱

  • 컴파일된 파일 및 결과물 캐싱
    • Next.js는 개발 서버를 실행하거나 프로젝트를 빌드할 때 소스 코드(JS/TS/SCSS 등)를 컴파일합니다. 이 과정에서 생성된 파일들을 .next 폴더에 저장하여 다음 빌드나 실행 시 중복 작업을 줄입니다.
    • 예: JavaScript 코드가 Babel/TypeScript에 의해 변환된 결과를 저장
  • HMR(Hot Module Replacement) 최적화
    • 개발 모드에서 코드 변경 시 변경된 부분만 빠르게 반영하기 위해 .next 폴더에 캐싱된 파일을 사용

빌드 결과물 저장

  • next build 명령어를 실행하면, 최종적으로 만들어진 정적 파일(HTML, CSS, JS 번들)이 .next 폴더에 저장됩니다.
  • 배포 시 이 폴더의 파일들이 클라이언트와 서버에 사용됩니다.

서버 사이드 렌더링(SSR) 데이터

  • 서버에서 렌더링된 HTML과 데이터를 포함한 프리렌더링 결과물이 .next에 저장됩니다. 이를 통해 서버와 클라이언트에서 효율적으로 콘텐츠를 제공할 수 있습니다.

.next 폴더의 구조

.next 폴더 내부에는 여러 하위 디렉토리와 파일이 있습니다. 주요 구성 요소를 살펴보겠습니다:

build

  • 빌드와 관련된 메타데이터를 저장합니다
  • Next.js가 빌드를 효율적으로 처리하기 위해 생성되는 내부 정보

cache

  • Next.js가 빌드, 컴파일, 번들링 과정에서 중복 작업을 방지하기 위해 생성한 캐시 파일
  • 개발 모드(next dev)나 빌드(next build)에서 공통적으로 사용됩니다

server

  • SSR(서버 사이드 렌더링)과 관련된 파일이 여기에 저장됩니다
  • 예: 페이지의 서버 렌더링 결과, API 라우트 핸들러, Edge Function 등의 데이터

static

  • 정적 리소스(CSS, JS, 이미지 등)와 같은 클라이언트에서 사용되는 파일이 저장됩니다
  • 번들링된 JavaScript 파일, 코드 스플리팅 결과물, 정적 최적화 결과물이 포함

routes

  • Next.js가 빌드한 페이지들의 경로 정보가 저장됩니다
  • 각 페이지에 대한 프리렌더링 정보와 관련된 파일이 포함

webpack

  • Next.js 내부적으로 Webpack을 사용해 코드를 번들링한 결과물
  • Webpack 설정과 관련된 캐싱 및 결과물이 저장됩니다

.next 폴더의 특징

  • 자동 생성 및 관리
    • Next.js를 실행(next dev, next build)하면 자동으로 생성됩니다
    • 사용자가 직접 수정할 필요는 없으며, Next.js가 자동으로 파일을 관리합니다
  • 삭제 가능:
    • .next 폴더를 삭제해도 프로젝트에는 영향을 주지 않습니다. 다만, 삭제 후 다시 실행하면 컴파일 및 빌드 과정이 처음부터 재실행됩니다.
  • 환경에 따라 다름
    • 개발 모드(next dev): 개발 중 HMR, 캐싱, 소스 맵 등을 위해 사용
    • 프로덕션 빌드(next build): 최적화된 정적 리소스와 서버 렌더링 파일을 포함

.next 폴더의 캐시와 관련된 주의점

  • 빌드 문제가 발생할 경우
    • 캐시된 데이터가 오래되거나 손상되면 빌드 또는 개발 서버에서 문제가 생길 수 있습니다. 이 경우 .next 폴더를 삭제한 후 다시 실행하면 문제가 해결되는 경우가 많습니다.
    • 명령어: rm -rf .next && next build
  • 캐시 정리:
    • 배포 환경에서는 매 빌드 시 새로운 .next 폴더가 생성되므로, 이전 캐시 데이터가 남아있지 않도록 관리가 필요합니다.

정리

.next 폴더는 Next.js의 핵심 동작을 지원하는 빌드 파일과 캐시 데이터를 담고 있습니다.

  • 캐시 역할: 컴파일 결과물과 빌드 결과를 저장하여 빌드 속도와 개발 서버의 효율성을 높임
  • 빌드 산출물: 프로덕션 배포에 필요한 정적 파일과 SSR 결과물을 포함
 

Next.js의 Middleware는 요청이 완료되기 전에 실행되는 실행되는 서버 측 코드로 요청(Request)과 응답(Response)을 수정하거나 특정 로직을 적용할 수 있는 기능을 제공한다. 이는 클라이언트와 서버간의 데이터 흐름을 제어하거나 요청을 리다이렉트, 리라이트, 응답 제한 등을 적용하는데 유용하다. 

 

Middlware란? 

Middleware는 HTTP요청에 대한 중간 역할을 하며 Next.js애플리케이션에서 URL을 기반으로 로직을 실행할 수 있다. 요청을 변경하거나 응답을 조작하며 Next.js의 라우팅 및 SSR과 결합되어 강력한 제어 기능을 제공한다. 

 

Middleware의 주요역할 

- 리다이렉션: 특정 경로로 사용자를 리다이렉트한다. 

- Rewriting: URL을 변환하여 다른 경로로 요청을 전달한다. 

- 응답수정 : 헤더를 추가하거나 응답 내용을 직접 변경한다. 

- 인증 및 권한 : 사용자가 인증된 상태인지 확인한다. 

- 언어감지 : 요청의 헤더 정보를 기반으로 다국어 페이지를 제공한다. 

 

Middleware의 동작원리 

1. 클라이언트의 요청이 서버로 전달되면 Middleware가 요청을 가로챈다. 

2. Middleware는 요청에 대해 조건문을 사용하여 특정 동작을 수행할지 결정한다. 

3. 요청이 수정되거나 응답이 생성된 후, Next.js의 나머지 서버 로직이 실행된다. 

 

Middleware함수의 구조 

Middleware는 기본적으로 next/server에서 제공되는 NextResponse객체와 함께 사용된다. 

import { NextResponse } from "next/server";

export function middleware(request) {
  // 로직 처리
  if (request.nextUrl.pathname === "/protected") {
    return NextResponse.redirect(new URL("/login", request.url));
  }

  return NextResponse.next(); // 요청을 계속 진행
}

요청 흐름 

1. 클라이언트 -> Middleware(요청 처리)

2. Middleware -> 필요한 경우 수정된 요청 전달 

3. Next.js서버 로직 -> 클라이언트 응답 

 

Middleware에서 사용할 수 있는 주요 객체

request 객체

  • 클라이언트의 요청 정보를 포함
  • request.nextUrl: URL 정보를 가져오기 위한 유틸리티
  • request.headers: 요청 헤더에 접근 가능
  • request.cookies: 쿠키 정보 접근 가능

NextResponse 객체

  • 응답을 생성하거나 수정할 때 사용
  • 주요 메서드
    • NextResponse.next(): 요청을 계속 진행
    • NextResponse.redirect(url): 특정 URL로 리다이렉트
    • NextResponse.rewrite(url): 요청을 다른 경로로 재작성
    • NextResponse.json(data): JSON 형식의 응답 반환

Middleware의 기본 설정

Middleware는 프로젝트의 middleware.js 또는 middleware.ts 파일에 정의됩니다. 이 파일은 Next.js의 루트 디렉토리 또는 특정 경로에 위치해야 합니다.

// 프로젝트 루트의 middleware.js
import { NextResponse } from "next/server";

export function middleware(request) {
  // 예제: 특정 페이지로 리다이렉트
  if (request.nextUrl.pathname.startsWith("/admin")) {
    return NextResponse.redirect(new URL("/login", request.url));
  }
  return NextResponse.next();
}

// 특정 경로에만 적용
export const config = {
  matcher: "/admin/:path*", // '/admin'으로 시작하는 모든 경로에 적용
};

Middleware의 고급 기능

Matcher

config.matcher를 사용하여 Middleware가 적용될 경로를 제어합니다.

export const config = {
  matcher: [
    "/about/:path*", // '/about' 경로와 하위 경로에 적용
    "/dashboard/:path*", // '/dashboard' 경로와 하위 경로에 적용
  ],
};

Rewriting

요청 URL을 변환하여 다른 경로로 라우팅합니다.

import { NextResponse } from "next/server";

export function middleware(request) {
  const url = request.nextUrl.clone();
  if (url.pathname === "/old-route") {
    url.pathname = "/new-route"; // URL을 '/new-route'로 변경
    return NextResponse.rewrite(url);
  }
  return NextResponse.next();
}

쿠키와 헤더 관리

Middleware를 사용하여 쿠키를 읽고 설정하거나, 응답 헤더를 수정할 수 있습니다.

import { NextResponse } from "next/server";

export function middleware(request) {
  const response = NextResponse.next();

  // 쿠키 추가
  response.cookies.set("token", "12345", { httpOnly: true });

  // 헤더 추가
  response.headers.set("x-custom-header", "Hello World");

  return response;
}

사용 사례

인증이 필요한 경로 보호

로그인되지 않은 사용자를 /login으로 리다이렉트.

import { NextResponse } from "next/server";

export function middleware(request) {
  const isLoggedIn = request.cookies.get("isLoggedIn");
  if (!isLoggedIn && request.nextUrl.pathname.startsWith("/protected")) {
    return NextResponse.redirect(new URL("/login", request.url));
  }
  return NextResponse.next();
}

다국어 지원

사용자의 Accept-Language 헤더를 기반으로 언어를 감지하고 리다이렉트.

import { NextResponse } from "next/server";

export function middleware(request) {
  const locale = request.headers.get("accept-language")?.split(",")[0] || "en";
  request.nextUrl.locale = locale;
  return NextResponse.next();
}

API 요청 로깅

API 요청을 모니터링하거나 로그를 기록.

export function middleware(request) {
  console.log(`API 요청 경로: ${request.nextUrl.pathname}`);
  return NextResponse.next();
}

제약 사항

  1. Middleware는 Edge Runtime에서 실행되며, Node.js API를 사용할 수 없습니다. (예: fs 모듈)
  2. 응답은 항상 스트리밍 방식으로 처리됩니다.
  3. 빌드 시 middleware.js는 자동으로 Edge Function으로 배포됩니다.

휴 messenger App이 드디어 끝났다. 

 

장정 한달이 넘는 기간이었는데 솔직히 말하면 100%이해하지는 못했는데 그래도 전체적인 구조에 대해서 많이 배워가게 되었다.

이번에 진행해 볼 프로젝트는 금융 플랫폼을 만들어 보려고 한다. 

아무래도 요즘 은행에서도 IT채용을 많이 하고 있고 금융 플랫폼 만들어 본 경험이 매력적으로 보일 수 있겠구나 하는 생각으로 한 번 시도해보려고 한다. 

그래도 이전 보다 조금은 더 배웠으니깐 속도가 더 빨라지겠지?  

기본 개념

Django
Python 웹 프레임워크로, 웹 애플리케이션의 전반적인 백엔드 개발을 돕는 도구입니다. HTML 템플릿 렌더링, ORM(Object-Relational Mapping), 라우팅, 인증 등 웹 개발 전반에 필요한 도구를 제공합니다.

  • 사용 사례: 블로그, 커머스 사이트, 포럼 등.

Django REST Framework (DRF)
Django 위에 추가되는 라이브러리로, RESTful API를 쉽게 개발할 수 있게 도와줍니다. DRF는 JSON 응답, API 인증, 직렬화(Serialization) 등을 기본적으로 지원하며, Django ORM과 잘 통합됩니다.

  • 사용 사례: 모바일 앱 백엔드, 데이터 제공용 API 서버, SPA(Single Page Application) 백엔드.

기능 비교

기능  Django DRF 
템플릿 렌더링 HTML 페이지를 렌더링하는 데 적합 JSON이나 XML 같은 데이터 응답을 제공
직렬화 지원하지 않음 Serializer를 통해 Python 객체를 JSON으로 변환 (반대도 가능)
ORM 지원 Django ORM으로 데이터베이스 연동 Django ORM을 기반으로 직렬화와 통합
라우팅 URL 패턴 매핑 (장고의 urlpatterns) API 전용 라우터 (routers) 제공
인증 기본 인증 시스템 (세션, 사용자 관리) 토큰 기반 인증(JWT), OAuth 등 다양한 인증 방식 지원
목적 전통적인 웹 애플리케이션 개발 API 개발 전용
브라우저에서의 디버깅 기본 Django Admin 제공 API를 테스트할 수 있는 Browsable API UI 제공

코드 예시 비교

Django로 구현 (HTML 렌더링)

사용자 정보를 보여주는 HTML 페이지 작성.

# views.py
from django.shortcuts import render
from .models import User

def user_list(request):
    users = User.objects.all()
    return render(request, 'user_list.html', {'users': users})

# urls.py
from django.urls import path
from .views import user_list

urlpatterns = [
    path('users/', user_list, name='user_list'),
]

# user_list.html
<!DOCTYPE html>
<html>
  <body>
    <ul>
      {% for user in users %}
        <li>{{ user.name }}</li>
      {% endfor %}
    </ul>
  </body>
</html>

결과: /users/로 접속하면 사용자 리스트를 보여주는 HTML 페이지가 렌더링됩니다.

 

DRF로 구현 (JSON API)

사용자 정보를 제공하는 RESTful API 작성.

# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import User
from .serializers import UserSerializer

class UserListAPIView(APIView):
    def get(self, request):
        users = User.objects.all()
        serializer = UserSerializer(users, many=True)
        return Response(serializer.data)

# serializers.py
from rest_framework import serializers
from .models import User

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'name', 'email']

# urls.py
from django.urls import path
from .views import UserListAPIView

urlpatterns = [
    path('api/users/', UserListAPIView.as_view(), name='user_list_api'),
]

 

결과: /api/users/로 요청을 보내면 JSON 형식으로 사용자 데이터를 응답합니다

[
  {"id": 1, "name": "Alice", "email": "alice@example.com"},
  {"id": 2, "name": "Bob", "email": "bob@example.com"}
]

Django와 DRF를 함께 사용하는 이유

Django는 HTML 기반 웹 애플리케이션을 빠르게 개발하는 데 강력하지만, JSON과 같은 데이터를 주고받는 API 개발에는 적합하지 않습니다. DRF는 이를 보완하여 Django의 강력한 ORM과 인증 기능을 활용하면서도 RESTful API를 간단히 설계할 수 있도록 합니다.

  • Django로 전통적인 웹 페이지와 관리자(Admin) 페이지를 개발하고,
  • DRF로 모바일 앱이나 프론트엔드(SPA)와 통신하는 API를 추가 개발하는 방식으로 두 도구를 결합할 수 있습니다.

DRF의 장점

  1. 간편한 직렬화: Serializer 클래스로 데이터를 직렬화/역직렬화하는 작업이 쉽습니다.
  2. API 문서화: 자동으로 브라우저에서 테스트 가능한 UI 제공 (Browsable API).
  3. 다양한 인증 방식 지원: OAuth2, JWT 등.
  4. 필터링과 페이징: 데이터의 검색, 정렬, 페이지네이션 기능 내장.
  5. 확장성: 커스터마이징 가능한 강력한 구조.

6. 어떤 것을 선택해야 할까?

  • HTML 페이지 중심의 프로젝트라면 Django만으로 충분.
  • 모바일 앱 또는 React/Vue.js 같은 SPA와 통신할 API가 필요하다면 Django + DRF 조합 추천.

내가 처음 REST API에 대해서 알게된건 지난 여름에 DRF프레임워크를 사용할 때였다. 

그때 REST API라는 것에 대한 명확한 정의를 알지 못했었는데 오늘 한번 주제로 다루어 보면서 공부해보면 좋을 거 같다는 생각을 한다. 

REST API란?

REST API는 Representational State Transfer의 약자로, 웹 기반 애플리케이션 간 상호작용을 돕는 설계 방식입니다. API(Application Programming Interface)를 통해 클라이언트와 서버 간의 데이터를 주고받을 때 RESTful 원칙을 따릅니다.

주요 특징으로는 다음과 같습니다.

  • 리소스 기반: 모든 데이터(사용자, 게시글 등)를 리소스로 간주.
  • HTTP 메서드 사용: CRUD 동작을 HTTP 메서드로 표현.
    • GET: 리소스 조회
    • POST: 리소스 생성
    • PUT/PATCH: 리소스 수정
    • DELETE: 리소스 삭제
  • URI 설계: 리소스 경로는 직관적이고 의미 있게 작성.
    • 예: /users/123 (ID가 123인 사용자 정보)

REST의 6가지 설계 원칙

RESTful API를 설계할 때 따라야 하는 6가지 원칙도 중요합니다.

  1. Uniform Interface: 일관된 인터페이스 설계.
    • 각 엔드포인트가 동일한 방식으로 작동해야 함.
  2. Stateless: 상태 비유지.
    • 서버는 클라이언트 상태를 저장하지 않으며, 모든 요청은 독립적.
  3. Cacheable: 응답은 캐시 가능.
    • 클라이언트는 서버의 응답을 캐싱하여 성능 최적화.
  4. Client-Server Architecture: 클라이언트와 서버는 독립적으로 설계.
  5. Layered System: 계층화된 시스템.
    • 중간 서버(로드 밸런서, 프록시 등)를 사용할 수 있음.
  6. Code on Demand (Optional): 필요 시 클라이언트에서 코드를 실행.
    • 예: 자바스크립트 파일 제공.

 

REST API의 작동 방식

예시: 블로그 포스트 API

  • Base URL: https://api.myblog.com
  • 엔드포인트:
    • GET /posts → 모든 포스트 조회
    • GET /posts/1 → 특정 포스트(ID: 1) 조회
    • POST /posts → 새 포스트 생성
    • PUT /posts/1 → 특정 포스트 수정
    • DELETE /posts/1 → 특정 포스트 삭제

HTTP 요청과 응답

요청 예시 (POST /posts):

POST /posts HTTP/1.1
Host: api.myblog.com
Content-Type: application/json

{
  "title": "REST API란 무엇인가?",
  "content": "REST API에 대해 알아봅시다!"
}

응답 예시:

HTTP/1.1 201 Created
Content-Type: application/json

{
  "id": 101,
  "title": "REST API란 무엇인가?",
  "content": "REST API에 대해 알아봅시다!",
  "created_at": "2024-12-11T08:30:00Z"
}

REST API의 장단점

장점:

  • 직관적이고 간단함: HTTP 메서드와 URI를 사용하므로 쉽게 이해 가능.
  • 확장성: 클라이언트와 서버가 독립적이라 확장에 유리.
  • 플랫폼 독립성: JSON, XML 등 다양한 포맷 지원.

단점:

  • 엄격하지 않은 표준: RESTful API 구현 방식이 개발자마다 달라질 수 있음.
  • 복잡한 요청 시 처리 부담: 상태 비유지 원칙으로 인해 요청마다 필요한 데이터를 모두 포함해야 함.

REST와 RESTful의 차이

  • REST는 아키텍처 스타일이고, RESTful은 REST 원칙을 준수한 시스템을 의미합니다.
  • 모든 REST API가 RESTful한 것은 아닙니다. URI 설계나 상태 비유지 원칙 등을 어길 수 있기 때문이죠.

REST API 설계 시 주의할 점

  1. 명확하고 직관적인 URI:
    • 좋음: /users/123/posts
    • 나쁨: /getUserPosts?id=123
  2. 적절한 HTTP 상태 코드 사용:
    • 200: 성공
    • 201: 리소스 생성
    • 404: 리소스 없음
    • 500: 서버 오류
  3. 에러 처리:
    • 명확하고 일관된 에러 메시지 제공.
    • 예: { "error": "Post not found" }

실제 프로젝트에서 REST API 사용하기

  • Postman이나 cURL로 테스트하기: API를 직접 호출해보고 응답 확인.
  • Swagger와 같은 문서화 도구 사용: 개발자 간 협업을 위한 문서화.
  • JWT와 함께 보안 강화: 인증 및 권한 부여에 토큰 기반 접근 제어 사용.

 

캐싱이란 무엇인가? 

캐싱(Caching)은 데이터나 결과를 임시 저장소에 저장하여 동일한 데이터에 대한 반복적인 요청을 더 빠르게 처리할 수 있도록 하는 기술이다. 캐싱을 사용하면 데이터를 매번 새로 가져오거나 계산하지 않아도 되므로, 시스템의 성능을 최적화하고 응답속도를 높이며 자원소비를 줄일 수 있습니다. 

 

캐싱의 기본 동작 원리 

캐싱은 다음과 같은 단계를 거쳐 작동합니다. 

1. 요청 발생 : 사용자가 어떤 데이터를 요청합니다. 

2. 캐시확인: 시스템이 캐시에 해당 데이터가 저장되어 있는지 확인합니다. 

- 데이터가 캐시에 있다면 이를 캐시 히트(cache hit)라고 하며 캐시에서 데이터를 바로 반환합니다. 

- 데이터가 캐시에 없다면 이를 캐시 미스(cache miss)라고 하며 데이터 소스 (예: 데이터 베이스)에서 데이터를 가져옵니댜. 

3. 캐시에 저장 : 캐시에 데이터가 없는 경우 가져온 데이터를 캐시에 저장합니다. 

4. 응답 반환 : 데이터를 요청한 사용자에게 반환합니다. 

 

캐싱의 종류 

캐싱은 시스템의 계층과 데이터의 사용 목적에 따라 여러 유형으로 나눌 수 있습니다. 

1. 메모리 캐싱 

- 데이터를 RAM과 같은 빠른 메모리에 저장합니다. 

- 예 : Redis, Memcached

- 장점: 빠른 속도로 데이터를 제공합니다. 

- 단점: 데이터의 용량이 메모리 크기에 제한된다. 

2. 디스크 캐싱

- 데이터를 디스크에 저장하여 캐싱한다. 

- 브라우저의 http캐시 (이미지, CSS파일 등 ) 

- 장점 : 더 많은 데이터를 저장할 수 있다. 

- 단점 : 메모리 캐싱보다 속도가 느리다. 

3. 브라우저 캐싱 

- 사용자가 웹 페이지를 요청할 때 CSS, JS, 이미지와 같은 정적 파일을 브라우저에 캐싱한다. 

- 장점 : 서버 요청을 줄이고 웹페이지 로드 속도를 개선한다. 

- 단점: 캐시가 오래된 경우, 최신 버전의 파일을 사용하지 못할 수 있다. 

4. 애플리케이션 캐싱 

- 애플리케이션 코드에서 데이터를 캐싱하여 중복 작업을 방지한다. 

- 예: React의 상태관리 라이브러리 (Recoil, Redux)에서 사용하는 메모리 캐시 

5. 데이터베이스 캐싱 

- 데이터베이스 조회 결과를 캐싱하여 동일한 쿼리에 대한 중복 요청을 방지한다. 

- 예 : mysql Query cache, postgresql의 materialized view

6. 분산캐싱

- 대규모 시스템에서 여로 노드에 걸쳐 데이터를 캐싱한다. 

- 예 content delivery network, Redis Cluster

 

캐싱의 주요 전략 

1. TTL (Time To Live) 

- 캐시에 저장된 데이터가 유효한 시간을 설정한다. TTL이 지나면 데이터를 만료시킨다. 

- 예: 뉴스 데이터는 10분 동안만 캐싱.

2. LRU(Least Recently Used)

- 가장 오랫동안 사용되지 않은 데이터를 제거하는 알고리즘이다. 

- 메모리 캐시의 용량 제한이 있을 때 주로 사용한다. 

3. Write-Through

- 데이터를 캐시와 데이터베이스에 동시에 기록한다.

- 장점 : 캐시와 데이터 소스가 동기화된다. 

- 단점 : 쓰기 속도가 느려질 수 있다. 

4. Lazy Loading

- 캐시에 없는 데이터를 요청 시에만 로드하여 저장한다. 

- 장점 : 초기 로드 시간이 짧아진다. 

- 단점: 사용자가 데이터를 수정하면 캐시를 삭제한다. 

 

캐시의 장점 

1. 성능향상 

- 데이터를 빠르게 제공하여 응답시간을 줄인다. 

- 특히 데이터베이스 조회, API 호출이 많은 시스템에서 큰 효과를 발휘한다. 

2. 트래픽 감소 

- 동일한 데이터를 반복적으로 가져오는 작업을 줄여 네트워크 사용량을 감소시킨다. 

3. 비용절감 

- 서버 부하를 줄여 추가적인 리소스 비용을 절약할 수 있다. 

 

캐싱의 단점 및 주의점 

1. 데이터 일관성 문제 

- 캐시에 저장된 데이터가 원본 데이터와 다를 수 있다. 이를 방지하려면 적절한 갱신 정책이 필요하다. 

2. 캐시 메모리 한계 

- 캐시 크기가 제한되어 있어 오래딘 데이터를 제거하는 과정에서 중요한 데이터가 삭제 될 수 있다. 

3. 캐시 복잡성 

 - 캐싱 전략을 잘못 설정하면 오히려 성능에 악영향을 미칠 수 있다. 

4. 초기 로딩 시간 

- 캐시가 비어 있는 경우 초기 요청 시간이 길어질 수 있다. 

 

예시 : 브라우저 캐싱 

HTTP캐싱 헤더를 사용하여 브라우저에 캐시를 설정할 수 있다. 

1. Cache-Control 

Cache-Control: max-age=3600

- 리소스를 1시간 동안 (3600초)캐싱합니다. 

2. ETag

ETag: "abc123"

- 리소스의 버전을 식별하는 고유 값으로, 변경 여부를 확인합니다. 

 

캐싱이 사용되는 곳

  1. 웹 애플리케이션: React, Next.js에서 클라이언트 상태를 관리할 때.
  2. CDN(Content Delivery Network): 정적 자산(CSS, JS, 이미지) 제공.
  3. 데이터베이스: 쿼리 결과 캐싱.
  4. API 서버: 외부 API 호출 결과를 캐싱.

Get과 Post는 HTTP요청 메서드 중 가장 많이 사용되는 두가지로 각각의 목적과 동작 방식이 다릅니다. 

이에 대한 구체적인 내용들에 대해서 설명 하도록 하겠습니다. 

요청의 목적 

Get

- 데이터를 조회할 때 사용됩니다.

- 서버에 요청을 보내 특정 리소스나 데이터를 가져오는 데 목적이 있습니다. 

- 예를 들어 블로그 글읽기나 검색 결과를 가져오는 것이 이에 해당됩니다. 

POST 

- 데이터를 생성하거나 전송할 때 사용됩니다. 

- 서버에 데이터를 보내 새로운 리소스를 생성하거나 데이터를 처리하도록 요청합니다. 

- 예를 들어 회원가입, 로그인, 게시글 작성 등이 있습니다. 

데이터 전달방식 

Get

- 데이터가 URL의 쿼리 스트링으로 전달됩니다.

  형식http://example.com?key1=value1&key2=value2 

- 전달 가능한 데이터 크기가 제한적입니다. 

- URL에 데이터가 노출되므로 보안에 취약합니다. 

POST 

- 데이터가 HTTP요청의 Body에 담겨 전달됩니다.

- URL에 데이터가 표시되지 않으므로 GET보다 비교적 보안성이 높습니다. 

- 전송 가능한 데이터 크기에 제한이 거의 없으며, 파일 업로드 같은 대용량 데이터 전송도 가능합니다. 

캐싱 

GET

- 브라우저와 서버는 GET요청에 대해 캐싱을 지원합니다. 

- 동일한 요청이 반복될 경우 서버가 아닌 브라우저나 프록시에서 캐시된 데이터를 반환할 수 있습니다. 

- 정적 리소스인 이미지나 CSS파일 등을 가져오는 데에 적합합니다. 

POST

- 기본적으로 캐싱되지 않습니다.

- 요청마다 서버에서 처리되며 같은 데이터를 여러번 전송하더라도 항상 새로운 요청으로 간주됩니다. 

 

멱등성(Idempotency)

멱등성이란 처음 수행한 뒤 여러 차례 적용해도 결과를 변경시키지 않는 작업또는 기능의 속성을 뜻합니다. 즉 멱등한 작업의 결과는 한번 수행하든 여러 번 수행하든 같아야 합니다. 

https://namu.wiki/w/%EB%A9%B1%EB%93%B1%EC%84%B1

 

GET

- 멱등성을 가집니다.

- 동일한 GET 요청을 여러 번 보내도 서버의 상태는 변하지 않습니다.

- 예) GET /products 요청을 10번 보내도 상품 목록은 그대로입니다.

POST

- 멱등성이 없습니다.

- 동일한 POST 요청을 여러 번 보내면 서버의 상태가 바뀔 수 있습니다.

- 예) POST /create-order 요청을 3번 보내면 주문이 3번 생성될 수 있습니다.

사용 사례

GET

- URL에 전달할 데이터가 간단하고 민감하지 않을 때 사용합니다.

- 서버에 데이터를 요청해 정보를 조회할 때 사용합니다.

- 예:

검색어 전송: http://example.com/search?query=apple  

블로그 게시물 조회: http://example.com/posts/123  

POST

- 민감하거나 대용량의 데이터를 서버에 전송할 때 사용합니다.

- 서버에 리소스를 생성하거나 데이터를 처리할 때 사용합니다.

- 예: 로그인 요청, 파일 업로드, 게시물 작성

HTTP 요청의 예시

GET 요청

GET /search?query=apple HTTP/1.1
Host: example.com
  • URL에 데이터를 포함합니다.
  • 서버는 query 값을 받아 데이터를 반환합니다.

POST 요청

POST /login HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded

username=user&password=1234
  • 데이터는 요청 본문(Body)에 포함됩니다.
  • 서버는 Body의 데이터를 받아 처리합니다.

GET과 POST의 장단점

장점 - 간단하고 빠르며 캐싱 가능 - URL에 데이터 노출이 없어 보안성이 높음
단점 - 데이터 길이 제한, 보안 취약 - 캐싱 불가능, 상대적으로 느림

실무에서의 선택 기준

GET을 사용하는 경우

- 데이터를 조회하거나 검색 조건을 전달할 때

- URL 공유가 필요할 때 (예: 검색 결과를 북마크하거나 공유)

 

POST를 사용하는 경우

- 민감한 정보를 전송할 때 (로그인, 회원가입 등)

- 파일 업로드처럼 대용량 데이터를 처리할 때

- 서버에 상태 변화를 유발하는 요청을 보낼 때

 
 

 

 

 

 

 

 

+ Recent posts