대표적인 HTTP Header
1️⃣ 표현 헤더(Representation)
요청, 응답에 모두 사용되는 Header
실제 데이터를 전송할 때는 특정 형식으로 변환하여 보낸다
리소스에 대한 표현 정보 (어떤 데이터 형식으로 보낼지)를 나타낸다
Content-Type : 형식
전송할 데이터의 미디어 타입, 문자 인코딩을 나타낸다
text/html; charset=utf-8
application/json
Content-Encoding : 압축 방식
데이터를 압축 후 Encoding 헤더를 추가하면, 읽는 쪽에서 해당 정보로 압축을 해제한다
gzip
identity : 압축하지 않음을 나타낸다
Content-Language : 언어
데이터의 언어를 표현
ko
en
2️⃣ 컨텐츠 협상(Content Negotiation)
요청시에만 사용되는 Header
클라이언트가 선호하는 표현을 요청
우선 순위 존재
Quality Values 줄여서 q 값을 사용
0 ~ 1 사이의 값이 존재하며 1에 가까울수록 높은 우선순위
Value가 1인 경우 생략 가능
q가 생략되었다면 선언된 순서대로 우선순위를 가진다
구체적으로 선언된 것이 우선순위가 높다
Accept : 선호하는 미디어 타입
Accept-Charset : 선호하는 문자 인코딩
Accept-Encoding : 선호하는 압축 인코딩
Accept-Language : 선호하는 언어
3️⃣ 일반 정보
단순한 정보들을 나타내는 Header
From : 클라이언트 이메일 정보
Referer : 현재 요청된 페이지의 이전 웹 페이지 주소
User-Agent : 클라이언트 애플리케이션 정보(PC, Mobile 브라우저)
Server : 요청을 처리하는 ORIGIN 서버의 Software 정보
Date : HTTP 요청이 발생한 날짜와 시간
4️⃣ 특별 정보
Host : 요청한 도메인 정보
Location : 생성된 리소스 URI, 리다이렉트 주소
Allow : 허용 가능한 HTTP Method
Retry-After : 다음 요청까지 대기 해야하는 시간
5️⃣ 인증
Authorization : 클라이언트 인증 정보
WWW-Authenticate : 리소스에 필요한 인증 방법
6️⃣ Cookie
사용자 세션 관리, 광고 정보 트래킹에 많이 사용된다
HTTP는 Stateless 특성을 가지고 있어서 상태를 매번 보내주어야 한다
Cookie를 사용하여 모든 요청마다 상태를 전달한다
Set-Cookie : 서버에서 응답시 클라이언트로 Cookie 값 전달
Cookie : 클라이언트가 서버에서 받은 쿠키를 Cookie 헤더를 통해 전송
Secure : 해당 헤더가 적용되면 https인 경우에만 쿠키를 전송
HttpOnly : http 전송에만 사용
SameSite : 쿠키에 설정된 도메인이 같은 경우만 쿠키를 전송
7️⃣ Cache
캐시가 없다면 같은 요청에 대한 응답 데이터가 같아도 매번 데이터를 새로 다운로드 받는다
새로 다운로드 받는만큼 속도가 느려지고, 비용이 발생
Cache-Contro : 응답시 사용하는 헤더
Cache-Control : max-age
Cache-Control: no-cache
Cache-Control: no-store
if-modified-since : 캐시로 저장된 데이터 최종 수정일
Last-Modified : 데이터가 마지막으로 수정된 시간
ETag : 캐시용 데이터에 날짜, 시간이 아닌 이름을 지정한다
REST를 잘 준수하는 API로 HTTP 프로토콜을 사용하여 클라이언트와 서버 간의 통신을 통해 자원(Resource)을 관리한다
자원은 고유한 URI로 식별되며, HTTP 메서드(GET, POST, PUT, DELETE 등)를 통해 다양한 작업을 수행하며 요청과 응답은 일반적으로 JSON 또는 XML 형식으로 이루어진다
➡️ ❗HTTP API를 잘 설계하는 규칙❗
자원(Resource)을 이름(Name)으로 구분하여 해당 자원의 상태(정보)를 주고받는 것을 의미
➡️ URI를 통해 자원(Resource)을 명시하고, HTTP Method(POST, GET, PUT, DELETE,PATCH 등)를 통해 해당 자원에 대한 CRUD Operation을 적용하는 것을 REST라 칭한다

REST의 제약 조건에 따라 API를 등급화하는 방법
Level0 : 웹 서비스를 제공하기 위해 URL만 매핑해 놓은 상태
Level1 : 외부로 공개하려는 리소스에 대해서 의미있는 URL로 표현하기 시작한 단계. 사용자의 요청을 GET, POST로 대부분 처리하고 에러를 반환
Level2 : 우리가 제공하고자 하는 리소스를 적절하게 용도와 상태에 따라서 HTTP Methods에 맞게 설계하고 서비스하는 단계
Level3 : 데이터를 가지고 그 다음 작업에서 어떠한 작업을 할 수 있는지 상태 정보를 함께 넘겨준다
1️⃣ Consumer first : 개발자 중심의 설계방식보다 해당 API의 소비자 입장에서 간단하고 직관적인 API를 설계 해야한다
2️⃣ Make best use of HTTP : HTTP Method와 Request, Response, Header와 같은 HTTP의 장점을 살려서 개발 해야한다
3️⃣ Request methods : 최소한 성숙도 모델 Level2로는 사용하여야 한다
4️⃣ Response Status : 각각의 API 요청에 따라서 적절한 HTTP 상태코드가 전달되어야 한다
5️⃣ No secure info in URI : URI에는 사용자의 정보를 포함해서는 안된다
6️⃣ Use plurals : 제공하는 데이터에 대하여 단수가 아닌 복수형태로 쓰는것이 일반적
7️⃣ User nouns for resources : 모든 리소스는 가능하면 동사가 아닌 명사형태로 표시
8️⃣ For exceptions - define a consistent approach : 일괄적인 엔드포인트를 사용하는것이 좋다
웹 서버는 HTTP 기반으로 동작하며 정적 리소스(HTML, CSS, JS, 이미지 등)를 제공한다
정적 리소스란? : 리소스가 이미 완성된 채로 서버에 존재하여 원본 그대로 응답하는 데이터를 의미

1️⃣ NGINX

2️⃣ Apache

HTTP 기반으로 동작하며 웹 서버의 기능을 포함한다. 추가적으로 코드를 실행해서 Application 로직을 수행하고 DB와 상호작용하여 동적 컨텐츠를 생성한다

1️⃣ Tomcat - Spring Boot에 내장되어 있다

2️⃣ Jetty

3️⃣ Undertow

1️⃣ 실제로는 Web Server도 Application 로직을 포함할 수 있다
2️⃣ WAS는 Application 코드를 실행하는 것에 더욱 특화되어 있다
3️⃣ Java에서는 Servlet Container 기능을 제공하면 WAS 이다
WAS만 사용하는 경우

WAS가 너무 많은 역할을 담당한다 → 서버 과부하 발생 가능성 증가
실행에 가장 중요한 Application 로직이 정적 리소스로 인해 수행되지 않을 수 있다
WAS에 장애가 생기면 아무런 화면도 보여주지 못한다 → 오류 페이지를 클라이언트에게 응답할 수 없다
실제 웹 시스템 구성

정적 리소스는 Web Server에서 처리
Web Server는 Application 로직이 필요한 요청만을 WAS에 전달
실제 웹 시스템 구성의 장점✅

✅ 효율적으로 리소스를 관리할 수 있다
✅ 오류 화면을 제공할 수 있다
❗Servlet은 HTTP 프로토콜 기반 요청(Request) 및 응답(Response)을 처리하는데 사용된다❗
JAVA에서 Sevlet은 HttpServlet 클래스를 상속받아 구현되며, 웹 애플리케이션 개발의 핵심 기술 중 하나이다
HTTP POST 요청으로 HTML Form 데이터를 전송하는 상황 예시
회원가입 : POST + localhost:8080/api/users

HTTP Request Message 예시
POST /api/users HTTP/1.1
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded
userId=아이디&pssword=비밀번호
HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Content-Length: 3423
<html>
<body>
...
</body>
</html>
서버에서 처리해야 하는 작업

1️⃣ 서버와 TCP/IP 연결
2️⃣ HTTP Request Message 필요한 형태로 변환하여 읽기
HTTP Method 및 URL 분석
HTTP Header 분석
HTTP Message Body 읽기 및 변환
3️⃣ 분석한 결과를 통해 프로세스 실행
4️⃣ ❗비지니스 로직 실행❗
5️⃣ HTTP Response Message 생성
HTTP Start Line 생성
Header 생성
HTTP Message Body에 응답 데이터를 요청한 형식에 맞춰 응답
처리가 불가하다면 예외처리
6️⃣ 응답 전달
7️⃣ 연결 종료
Servlet을 지원하는 WAS를 사용한다면?
localhost:8080/example HTTP API를 호출하면 일어나는 일 예시
URL (/example)이 호출되면 service() 메서드가 실행된다
@WebServlet(name="ExampleServlet", urlPatterns = "/exmaple")
public class ExampleServlet extends HttpServlet { // HttpServlet을 상속받아 구현한다.
@Override
protected void service(
HttpServletRequest request, // HTTP 요청 정보를 쉽게 사용할 수 있게 만드는 Servlet
HttpServletResponse response // HTTP 응답 정보를 쉽게 제공할 수 있게 만드는 Servlet
) {
// application logic
}
}

1️⃣ WAS는 HTTP 요청 메세지를 기반으로 새로운 Request, Response 객체 생성
2️⃣ WAS는 만들어진 Request, Response 객체를 서블릿 컨테이너에 넘겨주며 ExampleServlet 객체 호출
3️⃣ ExampleServlet에서 비지니스 로직 처리
4️⃣ 응답에 필요한 정보를 개발자가 입력
5️⃣ WAS는 Response 객체 정보(개발자가 입력한 정보)로 HTTP 응답 메세지 생성
1️⃣ Request 객체에 담겨져있는 HTTP 요청 정보를 꺼내서 사용한다
2️⃣ 생성된 Response 객체에 HTTP 응답 정보를 입력
Servlet을 지원하는 WAS 내부에는 서블릿 컨테이너가 있다 ➡️ ❗서블릿을 초기화, 생성, 관리, 호출, 종료하는 역할을 수행❗
Servlet의 생명주기
Servlet은 서블릿 컨테이너가 생성 및 관리
WAS(서블릿 컨테이너 포함)가 종료될 때 Servlet도 함께 종료
Servlet 객체 생성시점

@WebServlet(name="ExampleServlet", urlPatterns = "/example")
public class ExampleServlet extends HttpServlet { // HttpServlet을 상속받아 구현한다.
@Override
protected void service(
HttpServletRequest request, // HTTP 요청 정보를 쉽게 사용할 수 있게 만드는 Servlet
HttpServletResponse response // HTTP 응답 정보를 쉽게 제공할 수 있게 만드는 Servlet
) {
// application logic
}
}
@WebServlet(name="Example2Servlet", urlPatterns = "/example2")
// 위와 같은 코드
@WebServlet(name="Example3Servlet", urlPatterns = "/example3")
// 위와 같은 코드
@WebServlet(name="Example4Servlet", urlPatterns = "/example4")
// 위와 같은 코드
Servlet Container가 하는 일
서블릿을 초기화, 생성, 관리, 호출, 종료하는 역할을 수행 → Servlet 객체를 싱글톤으로 관리
동시 요청에 대한 처리를 위해 Multi Thread를 지원
싱글톤이란?
객체를 하나만 생성하여 생성된 인스턴스를 공유하여 사용하는것을 의미
특정 클래스의 인스턴스가 여러개 생성되지 않도록 하여 자원의 낭비를 방지하고, 인스턴스를 공유함으로써 상태를 일관되게 유지하기 위함
하지만, 공유 변수 사용을 주의해야한다
❗애플리케이션 코드를 하나하나 순차적으로 실행하는 것❗
Java에서 main method를 실행하면 main이라는 이름을 가진 Thread가 실행되며 하나의 Thread는 한번에 하나의 코드 라인만 수행한다
동시 처리가 필요할 땐 Thread를 추가로 생성해야 한다
Servlet 객체의 호출
단일 요청 - Single Thread
1) 클라이언트 요청 및 TCP/IP 연결
2) Thread 할당 후 Servlet 호출
3) 응답 후 Thread 반환
동시 요청 - Single Thread
1) 첫번째 요청의 작업을 Single Thread가 수행중이다
2) 두번째, 세번째 요청이 들어오고 연결을 완료했다
3) Thread를 사용하기 위해 작업이 끝날때 까지 대기
4) 요청이 모두 사라질 때 까지 (대기 → 작업 수행 → 스레드 반환)작업을 반복
→ 만약, 첫번째 요청의 작업이 지연되거나 Error가 발생한다면 → 모든 요청이 Time out 오류가 발생
WAS는 동시 요청에 대한 처리를 위해 Multi Thread를 지원한다
1️⃣ 요청마다 새로운 Thread 생성
요청이 들어올 때 마다 Thread를 생성
요청 처리가 완료되면 Thread를 종료
✅ 장점
- 동시 요청을 처리할 수 있다
- 하나의 Thread에 지연등의 문제가 발생하여도 나머지 Thread는 정상적으로 동작한다
❌ 단점
- Thread 생성에 제한이 없고 생성 비용이 높다
- 수많은 동시 요청이 발생하면 리소스(Memory, CPU 등)부족으로 서버가 다운된다
-
Thread를 사용하면 Context Switching 비용이 발생
2️⃣ Thread Pool
이미 생성된 여러개의 Thread가 수영을 하며 쉬고있는 수영장과 같다
요청이 들어오면 Thread Pool에서 Thread를 받아 사용
사용 완료된 Thread는 Thread Pool에 반납

와! 어제 공부한 내용인데 하나두 모르겠어요! 정리 감사합니다!