이 글은 김영한님의 인프런 강의 '모든 개발자를 위한 HTTP 웹 기본 지식' 강의를 듣고 배운 것을 두고두고 보기 위해 정리하는 글이다.
🗓️ 2023.06.30 작성 ▽
❗️ HTTP 헤더
header-field = field-name ":" OWS field-value OWS (OWS: 띄어쓰기 허용)
field-name은 대소문자 구분 X
❗️ HTTP 헤더 용도
HTTP 전송에 필요한 모든 부가정보
ex) 메시지 바디의 내용, 메시지 바디의 크기, 압축, 인증, 요청 클라이언트, 서버 정보, 캐시 관리 정보, ,,,
표준 헤어가 많고 필요시 임의의 헤더 추가가 가능
❗️ HTTP 헤더 분류
RFC2616(과거) 헤더 분류
message body - RFC2616(과거)
그러나 HTTP 표준에서 RFC2616(1999년)이 폐기되고 RFC7230~7235(2014년)이 등장함
❗️ RFC723x
변화
message body - RFC7230(최신)
❗️ 표현
표현 헤더는 전송, 응답 둘다 사용
Content-Type
표현 데이터의 형식
미디어 타입, 문자 인코딩
ex) text/html; charset=utf-8, application/json, image/png, ,,,
Content-Encoding
표현 데이터의 압축 방식
표현 데이터를 압축하기 위해 사용
데이터를 전달하는 곳에서 압축 후 인코딩 헤더 추가
데이터를 읽는 쪽에서 인코딩 헤더의 정보로 압축 해제
ex) gzip, deflate, identity, ,,,
Content-Language
표현 데이터의 자연 언어
ex) ko, en, en-US, ,,,
Content-Length
표현 데이터의 길이
바이트 단위
Transfer-Encoding(전송 코딩)을 사용하면 Content-Length는 사용 X
❗️ 협상(콘텐츠 네고시에이션)
클라이언트가 선호하는 표현 요청
요청시에만 사용
Accept-Charset
클라이언트가 선호하는 문자 인코딩
Accept-Encoding
클라이언트가 선호하는 압축 인코딩
Accept-Language
클라이언트가 선호하는 자연 언어
한국어 브라우저를 사용한다면 기본 언어가 한국어가 아닌 서버에서도 한국어를 지원하는 서버라면 Accept-Language: ko로 한국어 언어 지원을 받을 수 있음
만약 한국어를 지원하지 않는 서버라면 서버의 기본 언어로 응답
🗓️ 2023.07.04 작성 ▽
HTTP는 무상태 프로토콜
클라이언트와 서버가 요청과 응답을 주고 받은 후에는 연결이 귾김
클라이언트가 다시 요청을 해도 서버는 이전 요청을 기억하지 못함
-> 로그인을 했어도 항상 다시 로그인?
쿠키 미사용 예로, 로그인을 해도 로그인을 하지 않은 것과 같은 응답을 받음
이 대안으로는 모든 요청에 사용자 정보를 포함하는 것이 있음
ex) GET /welcome?user=홍길동 HTTP/1.1
그러나 이와 같은 대안은 모든 요청에 민감한 정보인 사용자 정보가 포함되도록 개발해야한다는 단점이 있음
또한 브라우저를 완전히 종료하고 다시 연다면 초기화 됨
쿠키는 브라우저의 쿠키 저장소에 저장됨
사용자가 로그인을 한다면 응답 메시지에 "Set-Cookie: user=홍길동"과 같은 메시지를 포함하여 쿠키를 저장할 수 있음
쿠키가 저장된 이후부터는 쿠키 저장소에서 조회된 사용자 정보로 로그인을 한 서비스를 받을 수 있음
보안에 민감한 데이터는 저장하면 안됨
모든 요청에는 쿠키 정보가 자동으로 포함 됨("Cookie: user=홍길동")
-> 최소한의 정보만 사용하여 네트워크 트래픽 최소화
쿠키 생명주기
Expires, max-age를 이용해 쿠키의 생명주기를 정해줄 수 있음
ex) Set-Cookie: expires=Sat, 26-Dec-2020 04:39:21 GMT(만료되면 쿠키 삭제), Set-Cookie: max-age=3600(3600초 후 쿠키 삭제, 값에 0이나 음수를 지정하면 쿠키 삭제)
세션 쿠키: 만료 날짜를 생략하면 브라우저 종료시 까지만 유지
영속 쿠키: 만료 날짜를 입력하면 해당 날짜까지 유지
domain
쿠키가 사용될 도메인을 지정
domain=example.org라면 dev.example.org도 쿠키 접근 가능
example.org에서 domain지정을 하지 않고 쿠키를 생성한다면 dev.example.org에서는 접근 불가
path
경로 지정
path=/home을 지정한다면 /home/level1, /home/level1/level2 등 하위 경로 페이지 쿠키 접근 가능
/hello -> 불가능
일반적으로 path=/ 처럼 루트로 지정
보안
Secure: 적용하면 https인 경우만 전송(원래 http, https 구분 X)
HttpOnly: XSS 공격 방지, 자바스크립트에서 접근 불가(document.cookie). HTTP 전송에만 사용
SameSite: XSRF 공격 방지, 요청 도메인과 쿠키에 설정된 도메인이 같은 경우만 쿠키 전송
❗️ 캐시가 없을 때
캐시가 없다면 어떠한 파일을 요청했을 때 서버에서 항상 파일을 내려줌
단점
❗️ 캐시 적용
max-age값(초단위)동안 다시 요청이 들어온다면 파일을 내려주지 않고 브라우저 캐시에서 그대로 파일을 가져옴
장점
캐시 시간이 초과한 경우 서버에서 다시 파일을 내려주고 max-age값이 다시 초기화됨
❗️ 캐시 시간 초과
캐시 유효 시간이 초과해서 서버에 다시 요청하면 다음 두 가지 상황이 나타남
1번의 경우(캐시 만료후에도 서버에서 데이터를 변경하지 않은 경우) 데이터를 전송하는 대신 저장해 두었던 캐시를 재사용
이 경우 클라이언트의 데이터와 서버의 데이터가 같다는 사실을 확인할 수 있는 방법이 필요
-> 검증 헤더 추가
❗️ 검증 헤더 추가
Last-Modified 헤더로 마지막으로 데이터가 수정된 시간을 받아올 수 있음
첫 번째 요청시 파일을 내려받음과 동시에 Last-Modified 값을 받음
캐시 시간이 초과되지 않으면 브라우저 캐시에서 파일을 가져오고, 아니면 서버에 요청
이때 if-modified-since 헤더로 만약 최종 수정일이 같다면(데이터가 수정되지 않았다면) 서버에서 304 Not Modified를 반환
이때 HTTP Body(파일 값)은 없기 때문에 파일의 용량만큼 절약이 됨
이때 다시 캐시 유효 시간이 초기화 됨
❗️ 정리
❗️ 검증 헤더
캐시 데이터와 서버 데이터가 같은지 검증하는 데이터
ex) Last-Modified, ETag
❗️ 조건부 요청 헤더
검증 헤더로 조건에 다른 분기
ex) If-Modified-Since: Last-Modified 사용, If-None-Match: ETag 사용
조건이 만족하면 200 OK
조건이 만족하지 않으면 304 Not Modified
❗️ Last-Modified, If-Modified-Since 단점
❗️ ETag(Entity Tag), If-None-Match
ETag는 캐시용 데이터에 임의의 고유한 버전 이름을 달아둔 것
ex) ETag: "v1.0", ETag: "a2jiodwjekjl3"
데이터가 변경되면 ETag는 바뀜(Hash를 다시 생성)
ex) ETag: "aaaaa" -> Etag: "bbbbb"
단순히 ETag가 만 보내서 같으면 유지, 다르면 다시 다운로드
같다면 응답 메시지에 HTTP Body가 없고 304 Not Modified
캐시 제어 로직을 서버에서 완전히 관리함
클라이언트는 단순히 이 값을 서버에 제공(클라이언트는 서버 캐시 메커니즘을 모름)
ex) 서버는 베타 오픈 기간인 3일 동안 파일이 변경되어도 ETag를 동일하게 유지, 애플리케이션 배포 주기에 맞춰 ETag 모두 갱신
❗️ 캐시 제어 헤더
Cache-Controle
캐시 지시어(directives)
Cache-Control: max-age: 캐시 유효 시간, 초 단위
Cache-Control: no-cache: 데이터는 캐시해도 되지만, 항상 원(origin) 서버에 검증하고 사용
Cache-Control: no-store: 데이터에 민감한 정보가 있어 저장하면 안됨(메모리에서 사용하고 최대한 빨리 삭제)
Pragma
캐시 제어(하위 호환)
이제는 대부분 쓰이지 않음
PRAGMA: no-cach: HTTP 1.0 이하에서 사용
Expires
캐시 만료일 지정(하위 호환)
캐시 만료일을 정화한 날짜로 지정
HTTP 1.0 부터 사용
지금은 더 유연한 Cache-Control: max-age 권장(함께 사용하면 Expires가 무시됨)
expires: Mon, 01 Jan 1990 00:00:00 GMT
❗️ 검증 헤더와 조건부 요청 헤더
검증 헤더 (Validator)
ETag: "v1.0", ETag: "asdid93jad"
Last-Modified: Thu, 04 Jun 2020 07:19:24 GMT
조건부 요청 헤더
If-Match, If-None-Match: ETag 값 사용
If-Modified-Since, If-Unmodified-Since: Last-Modified 값 사용
미국에 있는 원 서버(Origin 서버)에 항상 직접 접근한다고 가정
네트워크 통신 비용이 높음
그러나 한국 어딘가에 프록시 캐시 서버가 있다면?
첫 요청에 원 서버에서 프록시 캐시 서버로 데이터가 보내지고 프록시 캐시 서버에서 개인 웹 브라우저 데이터가 보내짐
처음에는 같은 비용이 발생하지만 프록시 캐시 서버에 캐시가 존재한다면 원 서버에 직접 통신을 했을 때보다 비용이 매우 낮아짐
프록시 캐시 서버의 캐시를 public 캐시, 개인 웹 브라우저의 캐시를 private 캐시라고 함
Cache-Controle: public: 응답이 public 캐시에 저장되어도 됨
Cache-Controle: private: 응답이 해당 사용자만을 위한 것임, private 캐시에 저장해야 함(기본값)
Cache-Controle: s-maxage: 프록시 캐시에만 적용되는 max-age
Age: 60 (HTTP 헤더): 오리진 서버에서 응답 후 프록시 캐시 내에 머문 시간(초)
확실한 캐시 무효화
위에서 설명한 Cache-Control: no-cache, Cache-Control: no-store, Pragma: no-cache도 캐시 무효화 옵션
Cache-Control: must-revalidate 옵션은 캐시 만료 후 최초 조회시 원 서버에 검증해야하고 원 서버 접근 실패시 반드시 오류가 발생해야 함 (504 Gateway Timeout)
또한 캐시 유효 시간이라면 캐시를 사용함
no-cache 기본 동작
must-revalidate 기본 동작
여기까지 김영한님의 이번 강의는 마무리가 되었다.
웹 개발자라면 기본적으로 알아야할 HTTP 지식들을 정말 접근하기 좋게 알려주신 것 같다.
김영한님은 개발계의 현우진이라는 말이 있다.
강의를 들으면 들을수록 그 말이 정말 공감이 되고 항상 감사한 마음이 든다.
모두 김영한님 강의 들으세요~~~
얻는 것에 비하면 진짜 가격도 싸다고 느껴집니다!!!!
이 다음부터는 고재성님, 이상훈님이 저자이신 "IT 엔지니어를 위한 네트워크 입문" 책을 읽을 예정이다.
이 또한 공부하면서 블로그에 정리노트를 포스팅 할 예정이다!