본문 바로가기

NETWORK & PROTOCOL

[PROTOCOL] HTTP

 HTTP(HyperText Transfer Protocol : 초본문전송규약, 하이퍼본문전송규약)는 W3 상에서 정보를 주고받을 수 있는 프로토콜이다. 주로 HTML 문서를 주고받는 데에 쓰인다. 주로 TCP를 사용하고 HTTP/3 부터는 UDP를 사용하며, 80번 포트를 사용한다.

 

HTTP METHOD 요청에 BODY가 있음 응답에 BODY가 있음 멱동
(idempotent)
캐시가능
GET 아니요
HEAD 아니요 아니요
POST 아니요
PUT 아니요
DELETE 아니요 아니요
CONNECT 아니요 아니요
OPTIONS 선택 사항 아니요
TRACE 아니요 아니요
PATCH 아니요

 

- HTTP 프로토콜은 상태가 없는(stateless = 매번 새로운 연결) 프로토콜입니다.  클라이언트 정보를 저장하지 않는다. 대신 쿠키와 세션을 이용, 이러한 특징 덕택에 서버는 세션과 같은 별도의 추가 정보를 관리하지 않아도 되고, 다수의 요청 처리 및 서버의 부하를 줄일 수 있는 성능 상의 이점이 생깁니다.

 

- HTTP 프로토콜은 일반적으로 TCP/IP 통신 위에서 동작하며 기본 포트는 80번입니다.

 

 


 

Cache-Control

 

  • Client의 요청이 Cache Server 혹은 로컬 Cache 관리자에 전달됩니다.
  • 캐시 된 문서가 있는지를 조회합니다.
  • 존재한다면 문서의 유효성 체크를 하게 되고, 없다면 Server로 요청을 전달합니다.
  • 해당 문서가 아직 유효하다면, 새로 생성한 Headers와 기존의 Body를 조합합니다.
  • 유효하지 않다면, Server에 요청을 전달합니다.
  • Client에 응답을 전달합니다.

 

캐시의 생명 주기

HTTP에서 리소스(Resource)란 웹 브라우저가 HTTP 요청으로 가져올 수 있는 모든 종류의 파일을 말합니다. 대표적으로 HTML, CSS, JS, 이미지, 비디오 파일 등이 리소스에 해당합니다.

웹 브라우저가 서버에서 지금까지 요청한 적이 없는 리소스를 가져오려고 할 때, 서버와 브라우저는 완전한 HTTP 요청/응답을 주고받습니다. HTTP 요청도 완전하고, 응답도 완전합니다. 이후 HTTP 응답에 포함된 Cache-Control 헤더에 따라 받은 리소스의 생명 주기가 결정됩니다.

 

캐시의 유효 기간: max-age

서버의 Cache-Control 헤더의 값으로 max-age=<seconds> 값을 지정하면, 이 리소스의 캐시가 유효한 시간은 <seconds> 초가 됩니다.

캐시의 유효 기간이 지나기 전

한 번 받아온 리소스의 유효 기간이 지나기 전이라면, 브라우저는 서버에 요청을 보내지 않고 디스크 또는 메모리에서만 캐시를 읽어와 계속 사용합니다.

 

예를 들어, 위 개발자 도구 캡처와 같이 어떤 JavaScript 파일을 요청하는 경우를 가정합시다. 이 리소스가 가지는 Cache-Control 헤더 값은 max-age=31536000 이기 때문에, 이 리소스는 1년(31,536,000초)동안 캐시할 수 있습니다.

 

스크린샷에서는 유효한 캐시가 메모리에 남아 있기 때문에 (from memory cache) 라고 표기된 것을 확인할 수 있습니다.

“서버에 요청을 보내지 않고” 라고 하는 말에 주의합시다. 한번 브라우저에 캐시가 저장되면 만료될 때까지 캐시는 계속 브라우저에 남아 있게 됩니다. 때문에 CDN Invalidation을 포함한 서버의 어떤 작업이 있어도 브라우저의 유효한 캐시를 지우기는 어렵습니다.

 

 

Note: Cache-Control max-age 값 대신 Expires 헤더로 캐시 만료 시간을 정확히 지정할 수도 있습니다.

 

 

캐시의 유효 기간이 지난 이후: 재검증

그렇다면 캐시의 유효 기간이 지나면 캐시가 완전히 사라지게 될까요? 그렇지는 않습니다. 대신 브라우저는 서버에 조건부 요청(Conditional request)을 통해 캐시가 유효한지 재검증(Revalidation)을 수행합니다.

재검증 결과 브라우저가 가지고 있는 캐시가 유효하다면, 서버는 [304 Not Modified] 요청을 내려줍니다. [304 Not Modified] 응답은 HTTP 본문을 포함하지 않기 때문에 매우 빠르게 내려받을 수 있습니다. 예를 들어, 위 스크린샷을 살펴보면 59.1KB 리소스의 캐시 검증을 위해 324바이트만의 네트워크 송수신만을 주고받았음을 볼 수 있습니다.

 
If-None-Match와 If-Modified-Since가 포함된 요청

대표적인 재검증 요청 헤더들로는 아래와 같은 헤더가 있습니다.

  1. If-None-Match: 캐시된 리소스의 ETag 값과 현재 서버 리소스의 ETag 값이 같은지 확인합니다.
  2. If-Modified-Since: 캐시된 리소스의 Last-Modified 값 이후에 서버 리소스가 수정되었는지 확인합니다.

위의 ETag 와 Last-Modified 값은 기존에 받았던 리소스의 응답 헤더에 있는 값을 사용합니다.

재검증 결과 캐시가 유효하지 않으면, 서버는 [200 OK] 또는 적합한 상태 코드를 본문과 함께 내려줍니다. 추가로 HTTP 요청을 보낼 필요 없이 바로 최신 값을 내려받을 수 있기 때문에 매우 효율적이죠. 

 

 

max-age=0 주의보 정의대로라면 max-age=0 값이 Cache-Control 헤더로 설정되었을 때, 매번 리소스를 요청할 때마다 서버에 재검증 요청을 보내야 할 것입니다. 그렇지만 일부 모바일 브라우저의 경우 웹 브라우저를 껐다 켜기 전까지 리소스가 만료되지 않도록 하는 경우가 있습니다. 네트워크 요청을 아끼고 사용자에게 빠른 웹 경험을 제공하기 위해서라고 합니다.

이 경우에는 웹 브라우저를 껐다 켜거나, 아래에서 소개할 no-store 값을 사용해주세요.

 

no-cache와 no-store

Cache-Control에서 가장 헷갈리는 두 가지 값이 있다면 바로 no-cache 와 no-store 입니다. 이름은 비슷하지만 두 값의 동작은 매우 다릅니다.

no-cache 값은 대부분의 브라우저에서 max-age=0 과 동일한 뜻을 가집니다. 즉, 캐시는 저장하지만 사용하려고 할 때마다 서버에 재검증 요청을 보내야 합니다.

no-store 값은 캐시를 절대로 해서는 안 되는 리소스일 때 사용합니다. 캐시를 만들어서 저장조차 하지 말라는 가장 강력한 Cache-Control 값입니다. no-store를 사용하면 브라우저는 어떤 경우에도 캐시 저장소에 해당 리소스를 저장하지 않습니다.

 

캐시의 위치

CDN과 같은 중간 서버를 사용할 때, 캐시는 여러 곳에 생길 수 있습니다. 서버가 가지고 있는 원래 응답을 CDN이 캐시합니다. CDN의 캐시된 응답은 사용자 브라우저가 다시 가져와서 캐시합니다. 이처럼 HTTP 캐시는 여러 레이어에 저장될 수 있기 때문에 세심히 다루어야 합니다.

CDN Invalidation

일반적으로 캐시를 없애기 위해서 “CDN Invalidation”을 수행한다고 이야기합니다. CDN Invalidation은 위 다이어그램에서 가운데에 위치하는 CDN에 저장되어 있는 캐시를 삭제한다는 뜻입니다. 브라우저의 캐시는 다른 곳에 위치하기 때문에 CDN 캐시를 삭제한다고 해서 브라우저 캐시가 삭제되지는 않습니다.

경우에 따라 중간 서버나 CDN이 여러 개 있는 경우도 발생하는데, 이 경우 전체 캐시를 날리려면 중간 서버 각각에 대해서 캐시를 삭제해야 합니다.

이렇게 한번 저장된 캐시는 지우기 어렵기 때문에 Cache-Control의 max-age 값은 신중히 설정하여야 합니다.

 

Cache-Control: public과 private

CDN과 같은 중간 서버가 특정 리소스를 캐시할 수 있는지 여부를 지정하기 위해 Cache-Control 헤더 값으로 public 또는 private을 추가할 수 있습니다.

public은 모든 사람과 중간 서버가 캐시를 저장할 수 있음을 나타내고,

private은 가장 끝의 사용자 브라우저만 캐시를 저장할 수 있음을 나타냅니다.

기존과 max-age 값과 조합하려면 Cache-Control: public, max-age=86400 과 같이 콤마로 연결할 수 있습니다.

 

s-maxage

중간 서버에서만 적용되는 max-age 값을 설정하기 위해 s-maxage 값을 사용할 수 있습니다.

예를 들어, Cache-Control 값을 s-maxage=31536000, max-age=0 (브라우저age=0, cdn age=31536000) 과 같이 설정하면 CDN에서는 1년동안 캐시되지만 브라우저에서는 매번 재검증 요청을 보내도록 설정할 수 있습니다.

 

토스에서의 Cache-Control

토스 프론트엔드 챕터는 리소스의 성격에 따라 세심히 Cache-Control 헤더 값을 조절하고 있습니다.

 

HTML 파일

일반적으로 https://service.toss.im/toss-card/introduction 과 같은 HTML 리소스는 새로 배포가 이루어질 때마다 값이 바뀔 수 있습니다. 때문에 브라우저는 항상 HTML 파일을 불러올 때 새로운 배포가 있는지 확인해야 합니다.

 

이런 리소스에 대해 토스 프론트엔드 챕터는 Cache-Control 값으로 max-age=0, s-maxage=31536000 을 설정했습니다. 이로써 브라우저는 HTML 파일을 가져올 때마다 서버에 재검증 요청을 보내고, 그 사이에 배포가 있었다면 새로운 HTML 파일을 내려받습니다.

CDN은 계속해서 HTML 파일에 대한 캐시를 가지고 있도록 했습니다. 대신 배포가 이루어질 때마다 CDN Invalidation을 발생시켜 CDN이 서버로부터 새로운 HTML 파일들을 받아오도록 설정했습니다.

JS, CSS 파일

JavaScript나 CSS 파일은 프론트엔드 웹 서비스를 빌드할 때마다 새로 생깁니다. 토스 프론트엔드 챕터는 임의의 버전 번호를 URL 앞부분에 붙여서 빌드 결과물마다 고유한 URL을 가지도록 설정하고 있습니다.

 
 
 

Server

아래는 Server가 Cache 관리를 제한하는 방법입니다.
 
Cache-Control: no-cache
캐시 관리자에게 캐싱을 허용하나, 사용 전 필수로 Server에 유효성 체크를 해야 합니다.
 
Cache-Control: no-store
캐싱을 금지합니다.
 
Cache-Control: max-age=3600
초 단위로 캐시가 유효한 시간을 제공합니다.
 
Cache-Control: must-revalidate
캐시 관리자에게 내부 유효성 체크를 허용하지 않으며, 항상 Server에 유효성 체크를 하도록 합니다.
 

Client

아래는 Client가 데이터를 요청 시에 Cache 관련 제어를 하는 방법입니다.
 
Cache-Control: max-stale
Client가 캐시관리자에게 유효시간이 지난 데이터를 반환 하는것을 허용합니다.
 
Cache-Control: max-stale=3600
Client가 캐시 관리자에게 제공한 시간 정도만 유효시간이 지난 데이터를 반환하는 것을 허용합니다.
 
Cache-Control: max-age=3600
캐시 관리자는 제공한 시간보다 오래된 데이터를 반환하지 않도록 요청합니다.
 
Cache-Control: no-cache
캐시 관리자에게 캐시 된 데이터를 반환하기 전에 Server에 유효성 체크를 하도록 요청합니다.
 
Cache-Control: no-store
캐시를 하지 않도록 요청합니다.


Accept-XXXXX  :  클라이언트가 이해할 수 있는 언어, 인코딩 

Connection 클라이언트와 서버 간 연결에 대한 옵션 설정
Ex) Connection: close 현재 HTTP 메시지 직후에 TCP 접속을 끊는다는 것을 알린다.  Connection: Keep-Alive 현재 TCP 커넥션을 유지한다 

Keep-Alive: timeout=5, max=99

= >5초 유지, 앞으로 99번 request 가능

 

 


Content-Type


Content-Type 해당 개체에 포함되는 미디어 타입 정보 컨텐츠의 타입(MIME 미디어 타입) 및 문자 인코딩 방식(EUC-KR,UTF-8 등)을 지정한다.

 

1) Multipart Related MIME 타입
  - Content-Type: Multipart/related <-- 기본형태
  - Content-Type: Application/X-FixedRecord


2) XML Media의 타입
 - Content-Type: text/xml
 - Content-Type: Application/xml
 - Content-Type: Application/xml-external-parsed-entity
 - Content-Type: Application/xml-dtd
 - Content-Type: Application/mathtml+xml
 - Content-Type: Application/xslt+xml


3) Application의 타입 
 - Content-Type: Application/EDI-X12 <--  Defined in RFC 1767 
 - Content-Type: Application/EDIFACT <--  Defined in RFC 1767 
 Content-Type: Application/javascript <-- Defined in RFC 4329 
 - Content-Type: Application/octet-stream  : <-- 디폴트 미디어 타입은 운영체제 종종 실행파일, 다운로드를 의미
 - Content-Type: Application/ogg <-- Defined in RFC 3534
 - Content-Type: Application/x-shockwave-flash <-- Adobe Flash files
 - Content-Type: Application/json <-- JavaScript Object Notation JSON; Defined in RFC 4627 
 - Content-Type: Application/x-www-form-urlencode <-- HTML Form 형태
* x-www-form-urlencode와 multipart/form-data은 둘다 폼 형태이지만 x-www-form-urlencode은 대용량 바이너리 테이터를 전송하기에 비능률적이기 때문에 대부분 첨부파일은 multipart/form-data를 사용하게 된다.


4) 오디오 타입
- Content-Type: audio/mpeg <-- MP3 or other MPEG audio
- Content-Type: audio/x-ms-wma <-- Windows Media Audio;
- Content-Type: audio/vnd.rn-realaudio <--  RealAudio;  등등 


5) Multipart 타입
- Content-Type: multipart/mixed: MIME E-mail; 
- Content-Type: multipart/alternative: MIME E-mail;
- Content-Type: multipart/related: MIME E-mail <-- Defined in RFC 2387 and used by MHTML(HTML mail) 
- Content-Type: multipart/formed-data  <-- 파일 첨부


6) TEXT 타입 
- Content-Type: text/css
- Content-Type: text/html
- Content-Type: text/javascript
- Content-Type: text/plain
Content-Type: text/xml


7) file 타입
- Content-Type: application/msword <-- doc
- Content-Type: application/pdf <-- pdf
- Content-Type: application/vnd.ms-excel <-- xls
- Content-Type: application/x-javascript <-- js
- Content-Type: application/zip <-- zip
- Content-Type: image/jpeg <-- jpeg, jpg, jpe
- Content-Type: text/css <-- css
- Content-Type: text/html <-- html, htm
- Content-Type: text/plain <-- txt
- Content-Type: text/xml <-- xml
- Content-Type: text/xsl <-- xsl


타입 및 서브타입(type/subtype)으로 구성된다. 타입(type): 10개 정도 표준으로 지정됨(application, audio, font, image, multipart 등) 서브타입(subtype): 각 타입별로 수십에서 수백개 정도

Ex) Content-Type: text/html; charset-latin-1 해당 개체가 html 텍스트 문서이고, iso-latin-1 문자 인코딩 방식으로 표현되는 것을 의미한다.

Content-Disposition 응답 Body를 브라우저가 어떻게 표시해야할지 알려준다. inline인 경우 웹페이지 화면에 표시되고, attachment인 경우 다운로드한다.

만약 Body에 담길 data가 커그나 다른 형식 HTTP response가 여러 번 나가야 한다면(multipart) 아래와 같은 형식으로 나가게 된다.

첫 번째 Content-Type: multipart/form-data;boundary="boundary"
두 번째 Content-Disposition: form-data; name="field1"
세 번째 Content-Disposition: form-data; name="field2"; filename="example.txt"

ex)

 

 


- 요청

headers

해당 request에 대한 추가 정보(addtional information)를 담고 있는 부분
예를 들어, request 메세지 body의 총 길이 (Content-Length) 등 Key:Value 형태로 구성

headers도 크게 3가지 부분으로 나뉨(general headers, request headers, entity headers)

Host: google.com
Accept: text/html
Accept-Encoding: gzip, deflate
Connection: keep-alive
...
  • Host 요청하려는 서버 호스트 이름과 포트번호
  • User-agent 클라이언트 프로그램 정보. 이 정보를 통해 서버는 클라이언트 프로그램(브라우저)에 맞는 최적의 데이터를 보내줄 수 있다.
  • Referer 바로 직전에 머물렀던 웹 링크 주소 
  • Accept 클라이언트가 처리 가능한 미디어 타입 종류 나열
  • If-Modified-Since 여기에 쓰여진 시간 이후로 변경된 리소스 취득. 페이지가 수정되었으면 최신 페이지로 교체한다.
  • Authorization 인증 토큰을 서버로 보낼 때 쓰이는 Header
  • Origin 서버로 Post 요청을 보낼 때 요청이 어느 주소에 시작되었는지 나타내는 값. 이 값으로 요청을 보낸 주소와 받는 주소가 다르면 CORS(Cross-Origin Resource Sharing) 에러가 발생한다.
  • Cookie 쿠키 값이 key-value로 표현된다.

 

body

HTTP Request가 전송하는 데이터를 담고 있는 부분

전송하는 데이터가 없다면 body 부분은 비어있습니다.

보통 post 요청일 경우, HTML 폼 데이터가 포함되어 있습니다.

POST /test HTTP/1.1

Accept: application/json
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 83
Content-Type: application/json
Host: google.com
User-Agent: HTTPie/0.9.3

{
    "test_id": "tmp_1234567",
    "order_id": "8237352"
}

 

 


- 응답

HTTP Response Message는 request와 동일하게 공백(blank line)을 제외하고 3가지 부분으로 나누어진다.

  • Status Line
  • Headers
  • Body

HTTP Response Message

 

status line

HTTP Response의 상태를 간략하게 나타내주는 부분

HTTP Response의 status line또한 3가지 부분으로 구성

  • HTTP version
  • Status Code
  • Status Text
HTTP/1.1 200 OK
[HTTP version] [Status Code] [Status Text]

headers

Response의 headers와 동일하다.

다만 response에서만 사용되는 header 값들이 있다.

예를 들어, User-Agent 대신에 Server 헤더가 사용된다.

 

body

Response의 body와 일반적으로 동일하다.

Request와 마찬가지로 모든 response가 body가 있지는 않다.

데이터를 전송할 필요가 없을경우 body가 비어있게 된다.

 

응답코드

2xx - 성공

200번대의 상태 코드는 대부분 성공을 의미합니다.

  • 200 : GET 요청에 대한 성공
  • 204 : No Content. 성공했으나 응답 본문에 데이터가 없음
  • 205 : Reset Content. 성공했으나 클라이언트의 화면을 새로 고침하도록 권고
  • 206 : Partial Conent. 성공했으나 일부 범위의 데이터만 반환

3xx - 리다이렉션

300번대의 상태 코드는 대부분 클라이언트가 이전 주소로 데이터를 요청하여 서버에서 새 URL로 리다이렉트를 유도하는 경우입니다.

  • 301 : Moved Permanently, 요청한 자원이 새 URL에 존재
  • 303 : See Other, 요청한 자원이 임시 주소에 존재
  • 304 : Not Modified, 요청한 자원이 변경되지 않았으므로 클라이언트에서 캐싱된 자원을 사용하도록 권고. ETag와 같은 정보를 활용하여 변경 여부를 확인

4xx - 클라이언트 에러

400번대 상태 코드는 대부분 클라이언트의 코드가 잘못된 경우입니다. 유효하지 않은 자원을 요청했거나 요청이나 권한이 잘못된 경우 발생합니다. 가장 익숙한 상태 코드는 404 코드입니다. 요청한 자원이 서버에 없다는 의미죠.

  • 400 : Bad Request, 잘못된 요청
  • 401 : Unauthorized, 권한 없이 요청. Authorization 헤더가 잘못된 경우
  • 403 : Forbidden, 서버에서 해당 자원에 대해 접근 금지
  • 405 : Method Not Allowed, 허용되지 않은 요청 메서드
  • 409 : Conflict, 최신 자원이 아닌데 업데이트하는 경우. ex) 파일 업로드 시 버전 충돌

5xx - 서버 에러

500번대 상태 코드는 서버 쪽에서 오류가 난 경우입니다.

  • 501 : Not Implemented, 요청한 동작에 대해 서버가 수행할 수 없는 경우
  • 503 : Service Unavailable, 서버가 과부하 또는 유지 보수로 내려간 경우

 

 

 

참조

 https://ko.wikipedia.org/wiki/HTTP

https://joshua1988.github.io/web-development/http-part1/

https://developer.mozilla.org/ko/docs/Web/HTTP/Messages

https://gmlwjd9405.github.io/2019/01/28/http-header-types.html

https://lannstark.tistory.com/8

HTTP메시지구조 - https://hahahoho5915.tistory.com/62#headers

캐시관련 - https://www.blog-dreamus.com/post/cache-control-%EC%9D%B4-%ED%95%84%EC%9A%94%ED%95%9C-%EC%9D%B4%EC%9C%A0

 

'NETWORK & PROTOCOL' 카테고리의 다른 글

[NETWORK] EJB  (0) 2023.03.30
[PROTOCOL] SOAP, FTP, SMTP, SSH  (0) 2021.06.28