🌍 네트워크

HTTP

HyperText Transfer Protocol

웹 통신 프로토콜. 요청-응답 모델. GET, POST, PUT, DELETE 메서드. HTTPS는 암호화 버전.

📖 상세 설명

HTTP(HyperText Transfer Protocol)는 웹에서 클라이언트와 서버 간 데이터를 주고받기 위한 애플리케이션 계층 프로토콜입니다. 1991년 Tim Berners-Lee가 WWW(World Wide Web)와 함께 개발했으며, 현재 인터넷 트래픽의 대부분이 HTTP를 통해 전송됩니다. 웹 브라우저가 서버에 요청(Request)을 보내면, 서버가 응답(Response)을 반환하는 요청-응답 모델로 작동합니다.

HTTP는 무상태(Stateless) 프로토콜입니다. 각 요청은 독립적이며 서버는 이전 요청을 기억하지 않습니다. 이 특성 덕분에 서버 확장이 쉽지만, 로그인 상태 유지 같은 기능을 위해 쿠키(Cookie)와 세션(Session)이 도입되었습니다. HTTP 메서드는 작업 유형을 나타내며, GET(조회), POST(생성), PUT(수정), DELETE(삭제)가 가장 많이 사용됩니다.

HTTP/1.0에서는 매 요청마다 TCP 연결을 새로 맺었지만, HTTP/1.1에서 Keep-Alive가 도입되어 하나의 연결로 여러 요청을 처리할 수 있게 되었습니다. HTTP/2는 멀티플렉싱, 헤더 압축, 서버 푸시 등을 지원하여 성능을 크게 개선했고, HTTP/3는 UDP 기반 QUIC 프로토콜을 사용하여 연결 설정 시간을 단축했습니다.

상태 코드(Status Code)는 요청 결과를 나타냅니다. 200(성공), 301/302(리다이렉트), 400(잘못된 요청), 401(인증 필요), 403(권한 없음), 404(찾을 수 없음), 500(서버 오류)이 대표적입니다. REST API 설계에서 올바른 상태 코드 사용은 클라이언트가 오류를 적절히 처리하는 데 필수적입니다. HTTPS는 TLS/SSL 암호화를 추가한 버전으로, 현대 웹에서는 HTTPS가 표준입니다.

💻 코드 예제

import requests

# GET 요청 - 데이터 조회
response = requests.get("https://api.github.com/users/octocat")
print(f"Status: {response.status_code}")  # 200
print(f"Content-Type: {response.headers['Content-Type']}")
data = response.json()
print(f"Username: {data['login']}")

# POST 요청 - 데이터 생성
payload = {"title": "New Post", "body": "Hello World", "userId": 1}
response = requests.post(
    "https://jsonplaceholder.typicode.com/posts",
    json=payload,
    headers={"Content-Type": "application/json"}
)
print(f"Created ID: {response.json()['id']}")  # 101

# PUT 요청 - 데이터 수정
response = requests.put(
    "https://jsonplaceholder.typicode.com/posts/1",
    json={"title": "Updated Title", "body": "Updated Body", "userId": 1}
)

# DELETE 요청 - 데이터 삭제
response = requests.delete("https://jsonplaceholder.typicode.com/posts/1")
print(f"Deleted: {response.status_code == 200}")

# 헤더 설정 & 인증
headers = {
    "Authorization": "Bearer YOUR_TOKEN",
    "User-Agent": "MyApp/1.0",
    "Accept": "application/json"
}
response = requests.get("https://api.example.com/data", headers=headers)

# 타임아웃 & 에러 처리
try:
    response = requests.get("https://api.example.com", timeout=5)
    response.raise_for_status()  # 4xx, 5xx 에러 시 예외 발생
except requests.exceptions.Timeout:
    print("Request timed out")
except requests.exceptions.HTTPError as e:
    print(f"HTTP Error: {e.response.status_code}")
# GET 요청 - 기본
curl https://api.github.com/users/octocat

# GET 요청 - 응답 헤더 포함
curl -i https://api.github.com/users/octocat

# GET 요청 - 상태 코드만 확인
curl -s -o /dev/null -w "%{http_code}" https://google.com

# POST 요청 - JSON 데이터
curl -X POST https://jsonplaceholder.typicode.com/posts \
  -H "Content-Type: application/json" \
  -d '{"title": "New Post", "body": "Hello", "userId": 1}'

# PUT 요청 - 데이터 수정
curl -X PUT https://jsonplaceholder.typicode.com/posts/1 \
  -H "Content-Type: application/json" \
  -d '{"title": "Updated", "body": "Changed", "userId": 1}'

# DELETE 요청
curl -X DELETE https://jsonplaceholder.typicode.com/posts/1

# 인증 헤더 추가
curl -H "Authorization: Bearer YOUR_TOKEN" https://api.example.com

# 쿠키 저장 & 사용 (세션 유지)
curl -c cookies.txt https://example.com/login  # 쿠키 저장
curl -b cookies.txt https://example.com/dashboard  # 쿠키 사용

# 응답 시간 측정
curl -w "Time: %{time_total}s\n" -o /dev/null -s https://google.com

# HTTP/2 강제 사용
curl --http2 https://www.google.com

# 상세 디버깅 (요청/응답 헤더 전체)
curl -v https://api.github.com/users/octocat

# CORS 프리플라이트 요청 시뮬레이션
curl -X OPTIONS https://api.example.com \
  -H "Origin: https://mysite.com" \
  -H "Access-Control-Request-Method: POST" -v
// Fetch API - GET 요청
const response = await fetch('https://api.github.com/users/octocat');
const data = await response.json();
console.log(`Username: ${data.login}`);
console.log(`Status: ${response.status}`);  // 200

// Fetch API - POST 요청
const postResponse = await fetch('https://jsonplaceholder.typicode.com/posts', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer YOUR_TOKEN'
    },
    body: JSON.stringify({
        title: 'New Post',
        body: 'Hello World',
        userId: 1
    })
});
const created = await postResponse.json();
console.log(`Created ID: ${created.id}`);

// PUT & DELETE 요청
await fetch('/api/posts/1', { method: 'PUT', body: JSON.stringify(data) });
await fetch('/api/posts/1', { method: 'DELETE' });

// 에러 처리 패턴
async function fetchWithErrorHandling(url) {
    try {
        const response = await fetch(url);
        if (!response.ok) {
            throw new Error(`HTTP ${response.status}: ${response.statusText}`);
        }
        return await response.json();
    } catch (error) {
        if (error.name === 'TypeError') {
            console.error('Network error or CORS issue');
        }
        throw error;
    }
}

// Axios (더 편리한 HTTP 클라이언트)
import axios from 'axios';

// 인스턴스 생성 (기본 설정)
const api = axios.create({
    baseURL: 'https://api.example.com',
    timeout: 5000,
    headers: { 'Authorization': 'Bearer TOKEN' }
});

// 인터셉터 (요청/응답 가로채기)
api.interceptors.response.use(
    response => response,
    error => {
        if (error.response?.status === 401) {
            // 토큰 갱신 로직
            return refreshTokenAndRetry(error.config);
        }
        return Promise.reject(error);
    }
);

🗣️ 실무에서 이렇게 말하세요

💬 API 설계 리뷰에서
"삭제 API인데 POST를 쓰면 혼란스럽습니다. RESTful하게 DELETE /users/{id}로 바꾸고, 성공 시 204 No Content를 반환하는 게 좋겠습니다. 만약 soft delete라면 200과 함께 삭제된 리소스를 반환해도 됩니다."
💬 프론트엔드 개발자와 협업 시
"CORS 에러가 나는 건 서버에서 Access-Control-Allow-Origin 헤더를 설정 안 해서예요. 개발 환경에서는 프록시로 우회하고, 프로덕션에서는 백엔드 팀에 화이트리스트 추가 요청하세요. preflight OPTIONS 요청도 허용해야 합니다."
💬 성능 최적화 논의에서
"현재 HTTP/1.1인데 HTTP/2로 업그레이드하면 멀티플렉싱 덕분에 여러 API를 동시에 요청해도 TCP 연결 하나로 처리됩니다. 또한 Cache-Control 헤더로 정적 리소스 캐싱하면 서버 부하를 70% 이상 줄일 수 있어요."

⚠️ 흔한 실수 & 주의사항

❌
GET 요청에 민감한 데이터 포함

GET 요청의 쿼리 파라미터는 URL에 노출되어 서버 로그, 브라우저 히스토리에 남습니다. 비밀번호, 토큰 같은 민감 정보는 반드시 POST body나 Authorization 헤더로 전송하세요.

❌
상태 코드를 항상 200으로 반환

에러 시에도 200을 반환하고 body에 에러 메시지만 담으면, 클라이언트가 자동 재시도나 에러 처리를 못 합니다. 400(잘못된 요청), 401(인증 필요), 404(없음), 500(서버 에러)를 정확히 구분하세요.

❌
타임아웃 설정 없이 요청

타임아웃 없이 요청하면 서버가 응답하지 않을 때 애플리케이션이 영원히 대기합니다. 일반적으로 API 요청은 5-30초, 파일 업로드는 더 길게 설정하세요. 재시도 로직도 함께 구현하세요.

✅
올바른 HTTP 활용법

HTTPS 필수 사용, 적절한 HTTP 메서드와 상태 코드 선택, Content-Type 명시, 타임아웃과 재시도 설정. 개발 시 curl -v나 브라우저 DevTools Network 탭으로 요청/응답을 항상 확인하세요.

🔗 관련 용어

📚 더 배우기