서버가 클라이언트의 이전 요청 정보를 기억하느냐의 차이다.
Stateful — 상대를 기억한다
서버가 클라이언트의 상태를 저장하고 유지한다. 이전 요청의 맥락을 알기 때문에 연속적인 흐름이 가능하다.
Stateless — 상대를 기억하지 않는다
모든 요청은 독립적이다. 서버는 이전 요청을 전혀 기억하지 않으며, 클라이언트가 매 요청마다 필요한 정보를 모두 담아 보내야 한다.
HTTP는 Stateless + Connectionless다.
개발 초기 메모리 비용이 높았고, 수많은 요청을 처리해야 했기 때문에 상태를 저장하지 않고 연결도 유지하지 않는 구조를 채택했다.
| Connection-oriented | Connectionless | |
|---|---|---|
| 연결 유지 | O | X |
| 자원 사용 | 높음 | 낮음 |
| 여러 명 동시 처리 | 어려움 | 용이함 |
| 적합한 상황 | 실시간 통신 | 일반 웹 요청 |
Connectionless의 단점 보완
매번 연결을 새로 맺는 비용(TCP 3-way Handshake)이 발생한다. 이를 해결하기 위해:
HTTP는 Stateless + Connectionless이기 때문에 서버가 먼저 클라이언트에게 데이터를 보낼 수 없다.
이게 문제가 되는 상황:

하나의 TCP 연결 위에서 양방향 통신을 가능하게 하는 프로토콜.
HTTP로 시작해 프로토콜을 갈아타는 방식(Handshake)으로 연결을 수립한다.
클라이언트 → 서버: Upgrade 요청 (HTTP)
서버 → 클라이언트: 101 Switching Protocols
이후: WebSocket 프레임으로 양방향 통신
| HTTP | WebSocket | |
|---|---|---|
| 통신 방향 | 단방향 (클라이언트→서버) | 양방향 |
| 연결 | 요청마다 끊김 | 유지 |
| 상태 | Stateless | Stateful |
| 프로토콜 시작 | HTTP | HTTP → WS로 교체 |
| URL scheme | http:// https:// | ws:// wss:// |
| 오버헤드 | 매 요청마다 헤더 전송 | 헤더 없이 프레임만 |
| 용도 | 일반 웹 페이지, API | 실시간 통신 |
프록시(Proxy): 클라이언트와 서버 사이의 중간 서버. 캐싱, 보안 필터링, 로드밸런싱 역할을 한다.

순서: 인증 → 인가. 누구인지 모르는데 권한을 줄 수 없다.
| 방식 | 특징 | 문제점 |
|---|---|---|
| 매번 ID/PW 전송 | 구현 간단 | PW가 매번 네트워크를 타고 다님 → 보안 취약 |
| 세션 | 서버가 상태 관리 | 서버 확장 어려움 (Stateful) |
| JWT | 클라이언트가 토큰 보관 | 토큰 탈취 시 만료 전까지 막을 수 없음 |
브라우저에 저장되는 작은 텍스트 파일. 서버가 발급하고, 이후 요청마다 브라우저가 자동으로 첨부한다.
1. 유저가 사이트 방문
2. 서버: "이 쿠키 들고 있어" → 브라우저에 저장
3. 이후 요청마다 브라우저가 쿠키를 자동 첨부
4. 서버: "아 이 사람이구나"
HttpOnly, Secure, SameSite 옵션을 반드시 설정해야 한다민감한 정보를 서버가 저장하고, 클라이언트에게는 세션ID(열쇠)만 발급한다.
로그인 → 서버가 세션 생성
서버 저장소: { "abc123": { user: "홍길동", role: "admin" } }
클라이언트: 세션ID "abc123"만 보유
다음 요청:
클라이언트 ──[Cookie: sessionId=abc123]──▶ 서버
서버: abc123 조회 → "홍길동이네" → 인증 완료
세션 저장 방식
| 방식 | 특징 |
|---|---|
| In Memory | RAM에 저장. 빠르지만 서버 재시작 시 사라짐. 실무에서 단독 사용 안 함 |
| Redis (In Memory DB) | 빠르면서 서버 여러 대가 공유 가능. 실무 표준 |
| File Storage | 디스크에 저장. 느림 |
취약점: Session Hijacking
세션ID가 탈취되면 공격자가 정상 유저로 인증을 통과할 수 있다. HttpOnly, Secure 쿠키 옵션으로 완화할 수 있다.
| 프레임워크 | 라이브러리 | |
|---|---|---|
| 제어권 | 프레임워크가 내 코드를 호출 | 내가 라이브러리를 호출 |
| 강제성 | 규칙을 따라야 함 | 필요한 것만 골라 씀 |
| 키워드 | 일관성 | 전문성 |
IoC(제어의 역전): 프레임워크의 핵심 특징. "내가 프레임워크를 쓰는 게 아니라, 프레임워크가 내 코드를 갖다 쓴다."
개발을 위한 구조와 규칙을 제공. 개발자는 그 안에서 비즈니스 로직만 채운다.
특정 기능을 구현해둔 코드 모음. 필요할 때 꺼내 쓴다.
| 이름 | 분류 | 이유 |
|---|---|---|
| Spring | 프레임워크 | 규제와 규약 제공, IoC 적용 |
| React | 라이브러리 | UI 렌더링만 담당, 자율성 보장 |
| Java Collection | 프레임워크 | 자료구조 구조·규칙 제공 |
| Socket.IO | 라이브러리 | 실시간 통신 기능만 제공 |

두 프로그램이 서로 통신하기 위해 정의한 규칙과 명세.
"이렇게 요청하면 이렇게 동작한다"는 약속이자 명세서
콘센트 비유: 전력망 내부 구조를 몰라도 규격(220V, 모양)만 맞추면 전기를 쓸 수 있다. API도 마찬가지로, 내부 구현을 몰라도 규칙만 맞추면 기능을 쓸 수 있다.
| 레고 비유 | 실제 의미 | |
|---|---|---|
| API Spec | 블록의 크기·모양·색상 규격 | "이 URL로, 이 형식으로 요청해라" |
| API Doc | 레고 사용 설명서 | "이 API는 이런 기능이고, 이렇게 쓴다" |
| 라이브러리 | 레고 블록 그 자체 | API Spec대로 실제 구현된 코드 |
실무에서 "API 만들어"라고 하면 99%는 REST API를 말한다.
| 규칙 | 예시 |
|---|---|
| URL은 자원을 표현 | /users, /products/123 |
| 행위는 HTTP 메서드로 | GET(조회), POST(생성), PUT(수정), DELETE(삭제) |
| Stateless | 매 요청은 독립적 |
데이터를 한 번에 전부 불러오면:
→ 필요한 만큼만 잘라서 가져오는 것이 페이징이다.
| 페이지네이션 | 인피니티 스크롤 | |
|---|---|---|
| UI | [1][2][3] 번호 클릭 | 스크롤 내리면 자동 로드 |
| 데이터 표시 | 현재 페이지로 교체 | 기존 데이터에 추가 |
| 적합한 곳 | 게시판, 검색결과 | 피드, 타임라인 |
| 대표 사례 | 구글 검색 | 인스타그램, 유튜브 |
1. Offset-based
SELECT * FROM posts LIMIT 10 OFFSET 20;
-- 20개 건너뛰고 10개 가져와
2. Page-based
offset = (page - 1) * limit
3. Key-based
-- Offset-based (느림)
SELECT * FROM posts LIMIT 10 OFFSET 1000000;
-- Key-based (빠름)
SELECT * FROM posts WHERE id > 1000000 LIMIT 10;
4. Cursor-based
5. Token-based
| 방식 | 속도 | 안정성 | 복잡도 | 적합한 상황 |
|---|---|---|---|---|
| Offset | 느림 | 낮음 | 낮음 | 소규모 게시판 |
| Page | 느림 | 낮음 | 낮음 | 페이지 네비게이션 UI |
| Key | 빠름 | 높음 | 중간 | 인피니티 스크롤 |
| Cursor | 빠름 | 높음 | 중간 | 보안이 필요한 피드 |
| Token | 빠름 | 높음 | 높음 | 보안 최우선 |
Offset → "느리고 중복 생긴다"
↓
Key → "빠르고 안정적. 근데 내부 ID가 노출된다"
↓
Cursor → "ID를 숨겼다. 근데 Base64라 뚫릴 수 있다"
↓
Token → "서버가 저장. 완전히 불투명하다. 근데 Stateful이 됐다"
완벽한 방식은 없다. 각 방식은 이전 방식의 단점을 해결하면서 새로운 트레이드오프를 가져온다.