HTTP
HyperText Transfer Protocol
웹 통신 프로토콜. 요청-응답 모델. GET, POST, PUT, DELETE 메서드. HTTPS는 암호화 버전.
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인데 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 요청의 쿼리 파라미터는 URL에 노출되어 서버 로그, 브라우저 히스토리에 남습니다. 비밀번호, 토큰 같은 민감 정보는 반드시 POST body나 Authorization 헤더로 전송하세요.
에러 시에도 200을 반환하고 body에 에러 메시지만 담으면, 클라이언트가 자동 재시도나 에러 처리를 못 합니다. 400(잘못된 요청), 401(인증 필요), 404(없음), 500(서버 에러)를 정확히 구분하세요.
타임아웃 없이 요청하면 서버가 응답하지 않을 때 애플리케이션이 영원히 대기합니다. 일반적으로 API 요청은 5-30초, 파일 업로드는 더 길게 설정하세요. 재시도 로직도 함께 구현하세요.
HTTPS 필수 사용, 적절한 HTTP 메서드와 상태 코드 선택, Content-Type 명시, 타임아웃과 재시도 설정. 개발 시 curl -v나 브라우저 DevTools Network 탭으로 요청/응답을 항상 확인하세요.