HTTP 헤더 개요
RFC2616 표준 (이었던 것)
- HTTP 헤더
- 용도: HTTP 전송에 필요한 모든 부가 정보
- header-field: field-name":" OWS field-value OWS
- OWS: 띄어쓰기 허용
- field-name은 대소문자 구분 없음
- 메세지 본문은 엔티티 본문을 전달하는 데 사용
- 엔티티 본문 (entity body)는 요청이나 응답에서 전달할 실제 데이터
- 엔티티 헤더는 엔티티 본문의 데이터를 해석할 수 있는 정보 제공
- 데이터 유형 (html, json), 데이터 길이, 압축 정보 등
2014년 RFC7230~7235 등장
- RFC2616 폐지
- Entity -> Representation (표현)
- 표현 = 표현 메타데이터 + 표현 데이터

- 메세지 본문을 통해 표현 데이터 전달
- 메세지 본문을 페이로드 (payload)라고도 한다.
- 표현은 요청이나 응답에서 전달할 실제 데이터
- 표현 헤더는 표현 데이터를 해석할 수 있는 정보 제공 (데이터 유형, 데이터 길이, 압축 정보 등등)
- (참고) 표현 헤더는 표현 메타데이터와 페이로드 메세지를 구분해야 하지만 ... 너무 복잡해지니까 생략
표현
- 표현이란: 리소스 (추상적인 것)을 서버와 클라이언트가 서로 주고받기 위해 구체화하는 것
- html 형식의 표현을 전달할 거야... 리소스를 json 형식으로 표현해서 전달할 거야...
표현 헤더의 요소
: 표현 헤더는 전송, 응답에 둘다 사용할 수 있다.
- Content-Type: 표현 데이터의 형식
- body에 들어가는 내용이 뭐야: html, json, ...
- 미디어 타입, 문자 인코딩 형식
- (예) text/html; charset=utf-8, application/json, image/png ...
- Content-Encoding: 표현 데이터의 압축 방식
- 표현 데이터를 압축하기 위해 사용
- 데이터를 전달하는 곳에서 압축한 뒤 인코딩 헤더 추가
- 데이터를 읽는 쪽에서 이 정보를 보고 압축을 해제해서 사용한다
- 데이터를 사용하려면 어떻게 압축되어 있는지 알아야 하기 때문에 필요
- (예) gzip(압축), deflate, identity(압축 전후가 똑같다: 압축 안 했다)...
- Content-Language: 표현 데이터의 자연 언어 (한국어인지 영어인지...)
- 표현 데이터의 자연 언어를 표현
- (예) ko, en, en-US
- 클라이언트가 요청 메세지의 Content-Language를 보고 언어마다 다른 페이지를 보여주거나... 하는 식으로 구현할 수도 있다.
- Content-Length: 표현 데이터의 길이
- 바이트 단위의 길이
- Transfer-Encoding (전송 코딩)이라는 게 있는데 요걸 사용하면 Content-Length를 사용하면 안됨.
- Transfer-Encoding 안에 이미 이 정보가 다 들어있기 때문에
콘텐츠 협상 (콘텐츠 네고시에이션)
- 클라이언트가 선호하는 표현 요청
- 협상 헤더는 요청 시에만 사용 (클라이언트 -> 서버)
- 원하는 대로 해달라고 요청했지만 서버가 못해줄 수도 있음 (!) 어쩔 수 없다.
- Accept: 클라이언트가 선호하는 미디어 타입 전달
- Accept-Charset: 클라이언트가 선호하는 문자 인코딩
- Accept-Encoding: 클라이언트가 선호하는 압축 인코딩
- Accept-Language: 클라이언트가 선호하는 자연 언어
- 원하는 언어로 달라고 요청
- 서버가 다중 언어로 되어 있고, 기본값이 영어일 때
- 요청 메세지에 국가 정보가 없으면 영어 페이지를 반환
- 요청 메세지에 Accept-Language: ko로 보내면 한국어 페이지를 반환 (만약 서버가 한국어를 가지고 있으면)
- 서버가 다중 언어로 되어 있고, 기본값이 독일어이고, 한국어가 없을 때
- Accept-Language를 ko로 보내도, 서버에 한국어 페이지가 없으니까 기본값인 독일어가 나옴 (쉽지않음)
- => 우선순위를 도입
- 한국어 -> 영어 순으로 되어 있는 우선순위로 보내면, 한국어가 없으니 다음 우선되는 언어로 영어를 선택해 보내준다
협상과 우선순위 (1)
- Quality Values (q) 값 사용
- 0~1, 1에 가까울수록 높은 우선순위를 가짐 (생략하면 1)

협상과 우선순위 (2)
- 구체적인 것이 우선한다.
- (예) Accept: text/, text/plain, text/plain;format=flowed, /*
- text/plain;format=flowed, text/plain, text/, /* 순으로 높은 우선순위를 갖는다.
협상과 우선순위 (3)
- 구체적인 것을 기준으로 미디어 타입을 맞춘다.

전송 방식
- 단순 전송
- Content-Length 사용: 컨텐츠의 길이를 알 수 있을 때 쓴다.
- 한 번에 요청하고 한 번에 단순하게 쭉 받는 것
- 압축 전송
- Content-Length, Content-Encoding 사용: 압축해서 보내는 것.
- 분할 전송
- Transfer-Encoding 사용: 분할 전송
- 바디에 청크의 길이/데이터 형식으로 분할해서 기록
- Content-Length를 넣으면 안된다.
(1) length를 예상할 수 없다.
(2) 청크마다 이미 length를 가지고 있다.
- 범위 전송
- Range, Content-Range 사용
- 일부는 이미 받아서 가지고 있고, 나머지만 전송받고 싶을 때 사용
일반 정보
- From: 유저 에이전트의 이메일 정보
- Referer: 이전 웹 페이지의 주소
- 현재 요청된 페이지의 이전 페이지의 주소
- A -> B로 이동하는 경우 B를 요청할 때 Referer A를 포함해서 요청
- 유입 경로 분석할 때 사용할 수 있다. 요청 메세지에 사용함.
- (참고) referer는 referrer의 오타...
- User-Agent
- 유저 에이전트 클라이언트 애플리케이션 정보
- 웹 브라우저 정보 등...
- 특정 브라우저에서 버그가 생기거나 사용자 경향을 확인하는 등 통계를 볼 때 사용할 수 있다.
- 요청 메세지에 사용함.
- Server: 요청을 처리하는 ORIGIN 서버의 소프트웨어 정보
- 오리진 서버: 중간에 거치는 프록시 서버들 말고 요청에 응답하는 진짜 서버를 오리진 서버라고 한다 (표현 데이터를 만들어 주는 서버)
- 응답 메세지에 사용
- Date: 메세지가 발생한 날짜와 시간
- 응답에서만 사용
- 과거에는 요청에서도 사용했지만 최신에는 응답에서만 사용
특별한 정보
- Host: 요청한 호스트 정보 (도메인)
- 요청에서 사용, 필수
- 하나의 서버가 여러 도메인을 처리해야 할 때
- 하나의 IP 주소에 여러 도메인이 적용되어 있을 때
- 호스트 헤더가 없는 요청을 보내면, 이런 상황들에서 어떤 도메인으로 처리해야 할지 알 수 없다. 그래서 호스트는 꼭 있어야 함!
- Location: 페이지 리다이렉션
- 웹 브라우저는 3xx 응답의 결과에 이 헤더가 있으면 Location 위치로 자동 이동한다.
- Allow: 허용 가능한 HTTP 메서드
- URL 경로는 있는데 GET, HEAD, PUT만 허용하고 POST는 지원하지 않을 때
- POST 요청이 오면, 405 (Method Not Allowed) 응답에 Allow 헤더를 포함시켜 돌려보내야 한다.
- Allow: GET, HEAD, PUT이라고 보내면 됨
- Retry-After 유저 에이전트가 다음 요청을 하기까지 기다려야 하는 시간
- 503 (Service Unavailable) 서비스가 언제까지 불능인지 알려줄 수 있음
- 서버 점검을 하거나... 그럴 때
- 종료 시점의 날짜 표기, 남은 시간을 표기 등
인증
- Authorization: 클라이언트 인증 정보를 서버에 전달
- 인증하는 여러가지 메커니즘이 있는데 그것마다 값이 다르다.
- WWW-Authentication
- 리소스 접근 시 필요한 인증 방법 정의
- 401 Unauthorized 응답에 넣어서 인증 방법을 클라이언트에게 알려 줘야 한다.
쿠키
- Stateless: 서버와 클라이언트가 서로의 상태를 유지하지 않음!
- 로그인을 하거나... 여러 상황에서, 문제가 생길 수 있음
- URL과 모든 요청에 서버가 필요로 하는 모든 정보를 적어서 보내면 된다
- 하지만 쉽지 않겠죠 (개발도 어렵고 보안 상의 문제도 있음)
- 브라우저를 완전히 종료하고 다시 열면 이 고생도 헛수고가 된다. (웹 스토리지라는 걸 써서 해결할 순 있지만 번거롭고 힘들다!)
쿠키의 등장
- 서버는 요청을 받으면, 쿠키를 만들어서 Set-Cookie 헤더에 적어 보냄.
- 클라이언트 (웹 브라우저)는 쿠키 저장소를 가지고 있음. 이렇게 받은 쿠키를 쿠키 저장소에 넣어둠.
- 클라이언트가 다시 요청을 보낼 때, 쿠키 저장소를 무조건 뒤져서 쿠키를 꺼내서 Cookie 헤더에 적어 보냄. (모든 요청 정보에 쿠키를 자동으로 포함)
- 서버는 이걸 보고 클라이언트의 이전 상태를 파악할 수 있음!
- 좋은 점: 쿼리문을 쓰거나 URL이 지저분해지거나 하지 않는다. 개발자도 편하고 좋다.
- 쿠키의 주 사용처: 사용자 로그인 세션 관리, 광고 정보 트래킹
- 쿠키 정보는 항상 서버에 전송됨
- 네트워크 트래픽 추가 유발 -> 최소한의 정보만 사용 (세션 id, 인증 토큰처럼 꼭 있어야 하는 것만 사용)
- 서버에 전송하지 않고, 웹 브라우저 내부에 데이터를 저장하고 싶으면 웹 스토리지를 사용하면 됨
- 쿠키는 일단 세팅하면 무조건 서버에 보내버리기 때문에... 클라이언트가 들고 있다가 필요할 때만 로직으로 꺼내 쓰고 싶을 때는 웹 스토리지 같은 것을 쓰면 된다.
- 주의!!!! 쿠키든 웹 스토리지든 보안에 민감한 데이터는 절대 저장하면 안됨.
- Set-Cookie: 서버에서 클라이언트로 쿠키 전달 (응답)
- 쿠키를 만들어서 보낼 때 제약 조건을 정해 놓는다.
- sessionId, expire (쿠키의 만료시점), path (쿠키가 허용되는 경로), Secure (쿠키의 보안 정보)
- Cookie: 클라이언트가 서버에서 받은 쿠키를 저장하고 HTTP 요청 시 서버로 전달
쿠키의 생명주기
- 쿠키가 영생을 살 순 없으니 끝나는 시점을 정해 준다. Set-Cookie에 넣어서 만들면 된다.
- expires=날짜 (GMT 기준)
- max-age=숫자 (초 단위)
- 세션 쿠키: 만료 날짜를 생략하면 브라우저 종료할 때까지만 유지
- 영속 쿠키: 만료 날짜를 입력하면 해당 날짜까지 유지
쿠키: 도메인
- Set-Cookie에 domain을 지정해서 보낼 수 있다. (domain=example.org)
- domain을 지정해 두면 지정된 도메인에서만 쿠키를 전송한다.
(1) 명시하는 경우: 명시한 문서를 기준으로 서브 도메인에도 쿠키를 보낸다.
(2) 생략하는 경우: 생성한 문서를 기준으로만 쿠키를 보낼 수 있음
- example.org에서 쿠키를 생성하고 domain을 생략하면 example.org에만 쿠키를 보냄.
쿠키: 경로
- path=/home
- 이 경로를 포함한 하위 경로 페이지만 쿠키에 접근할 수 있음
- 도메인으로 한 번 필터를 하고 도메인 안에서 경로를 한 번 더 필터링 하는 것
- 일반적으로 path=/루트로 지정
쿠키: 보안
- Secure
- 쿠키는 원래 http, https를 구분하지 않고 전송
- secure를 적용하면 https인 경우에만 전송
- HttpOnly
- XSS 공격 방지
- 자바스크립트에서 접근 불가
- HTTP 전송에만 사용
- SameSite
- XSRF 공격 방지
- 현재 내가 요청하는 도메인과 쿠키에 설정된 도메인이 완전히 같은 경우에만 쿠키를 전송함
- 기능이 적용된지 별로 되지 않아서 브라우저의 적용 범위를 확인한 뒤 사용할 것