HTTP 완벽 가이드 1부 - HTTP: 웹의 기초
Updated:
HTTP 완벽 가이드 시리즈를 정리한 내용입니다.
1장 HTTP 개관
1.2 웹 클라이언트와 서버
- 웹 서버는 HTTP 프로토콜로 의사소통하기 때문에 보통 HTTP 서버라고 불린다.
- 클라이언트가 웹브라우저를 통해 HTTP요청을 서버로 보내면, 서버는 요청받은 객체를 찾고 HTTP응답에 실어서 클라이언트에게 보낸다.
1.3 리소스
- 텍스트파일, HTML파일, JPEG 이미지 파일 과 같은 정적 파일 뿐 아니라 요청에 따라 콘텐츠를 생산하는 프로그램(동적 콘텐츠 리소스) 까지 모두 리소스가 될 수 있다.
1.3.1 미디어 타입
Content-type: image/jpeg
└MIME타입
- HTTP는 웹에서 전송되는 객체 각각에 MIME 타입이라는 데이터 포맷 라벨을 붙인다.
- 웹 브라우저는 서버로부터 객체를 받았을 때 MIME타입을 통해 다룰 수 있는지 확인한다.
- MIME타입은 사선(/)으로 구분된 주 타입과 부 타입으로 이루어진 문자열 라벨이다.
HTML : text/html
plain ASCII : text/plain
JPEG : image/jpeg
GIF : image/gif
1.3.2 URI
- 서버 리소스 이름은 URI(uniform resource identifier, 통합 자원 식별자) 라고 불린다.
http://www.joes-hardware.com/specials/saw-blade.gif
- URL, URN으로 세분화할 수 있다.
1.3.3 URL
- 특정 서버의 한 리소스에 대한 구체적인 위치를 서술한다.
http://www.joes-hardware.com/specials/saw-blade.gif
- 위 URL의 경우 스킴(http://)과 주소(www.joes-hardware.com), 리소스(/specials/saw-blade.gif)로 나눌 수 있다.
- 오늘날의 대부분의 URI는 URL이다.
1.3.4 URN
- 콘텐츠를 이루는 한 리소스에 대해, 그 리소스의 위치에 영향 받지 않는 유일무이한 이름 역할을 한다.
- 리소스의 위치가 변하더라도 영향을 받지 않는다.
- 아직 인프라의 부재로 인해 널리 채택되지 못했다.
1.4 트랜잭션
- HTTP 트랜잭션은 요청 명령과 응답 결과로 구성되어 있다.
1.4.1 메서드
- HTTP는 HTTP 메서드라고 불리는 여러가지 종류의 요청 명령을 지원하며, 요청 메세지는 한개의 메서드를 갖는다.
HTTP 메서드 | 설명 |
---|---|
GET | 서버에서 클라이언트로 지정한 리소스를 보내라. |
PUT | 클라이언트에서 서버로 보낸 데이터를 지정한 이름의 리소스로 저장하라. |
DELETE | 지정한 리소스를 서버에서 삭제하라. |
POST | 클라이언트 데이터를 서버 게이트웨이 애플리케이션으로 보내라. |
HEAD | 지정한 리소스에 대한 응답에서, HTTP 헤더 부분만 보내라. |
1.4.2 상태코드
- HTTP 응답 메세지는 상태 코드를 포함한다.
- 세자리 숫자와 사유 구절로 이루어진다.
1.5 메세지
- 요청 메세지 : 클라이언트 -> 서버
GET /test/hi-there.txt HTTP/1.0 시작줄
-------------------------------
Accept: text/* 헤더
Accept-Language: en,fr
- 응답 메세지 : 서버 -> 클라이언트
HTTP/1.0 200 OK 시작줄
------------------------------
Content-type: text/plain 헤더
Content-length: 19
------------------------------
Hi! I'm a message ! 본문
- 시작줄 : 요청이라면 무엇을 해야하는지, 응답이라면 무슨 일이 일어났는지 표기
- 헤더 : 0개 이상의 헤더 필드로 구성. 각 헤더 필드는 :으로 구분되어 하나의 이름과 하나의 값으로 구성. 빈줄로 헤더가 끝났음을 표시.
- 본문 : 모든 종류의 데이터가 포함될 수 있다.
1.6 TCP 커넥션
1.6.1 TCP/IP
- HTTP는 애플리케이션 계층 프로토콜이므로 네트워크 통신의 핵심적인 세부사항에 대해서는 신경쓰지 않는다.
- TCP/IP는 다음 기능들을 통하여 이를 대신한다.
- 오류 없는 데이터 전송
- 순서에 맞는 전달 (데이터는 언제나 보낸 순서대로 도착)
- 조각나지 않는 데이터 스트림 (언제든 어떤 크기로든 보낼 수 있음)
- TCP/IP : TCP와 IP가 층을 이루는, 패킷 교환 네트워크 프로토콜의 집합
- HTTP > TCP > IP 의 계층구조
1.6.2 접속, IP 주소 그리고 포트번호
- 클라이언트와 서버가 메세지를 주고받기 위해서는 IP주소와 포트번호를 사용해 TCP/IP 커넥션을 맺어야 한다.
- 통신 과정
- a. 웹브라우저는 서버의 URL에서 호스트 명을 추출
- b. 웹브라우저는 서버의 호스트 명을 IP로 변환(DNS)
- c. 웹브라우저는 URL에서 포트번호를 추출(없을 시 http는 80, https는 443)
- d. 웹브라우저는 웹 서버와 TCP 커넥션을 맺음(3-way handshake)
- e. 웹브라우저는 서버에 HTTP 요청을 보냄
- f. 서버는 웹브라우저에 HTTP 응답을 돌려줌
- g. 커넥션이 닫히면, 웹브라우저는 문서를 보여줌
2장 URL과 리소스
2.2 URL 문법
- 대부분의 URL 문법은 일반적으로 9개 부분으로 나뉜다.
<스킴>://<사용자 이름="">:<비밀번호>@<호스트>:<포트>/<경로>;<파라미터>?<질의>#<프래그먼트> 프래그먼트>질의>파라미터>경로>포트>호스트>비밀번호>사용자>스킴>
컴포넌트 | 설명 | 기본값 |
---|---|---|
스킴 | 리소스를 가져오려면 어떤 프로토콜을 사용하여 서버에 접근해야 하는지 가리킴 | 없음 |
사용자 이름 | 몇몇 스킴은 리소스에 접근을 하기 위해 사용자 이름을 필요로 함 | anonymous |
비밀번호 | 사용자의 비밀번호를 가리키며, 사용자 이름에 콜론(:)으로 이어서 기술한다. | <이메일 주소="">이메일> |
호스트 | 리소스를 호스팅하는 서버의 호스트 명이나 IP 주소 | 없음 |
포트 | 리소스를 호스팅하는 서버가 열어놓은 포트번호. 많은 스킴이 기본 포트를 가지고 있다. | 스킴에 따라 다름 |
경로 | 이전 컴포넌트와 빗금(/)으로 구분되어 있으며, 서버 내 리소스가 서버 어디에 있는지를 가리킨다. 경로 컴포넌트의 문법은 서버와 스킴에 따라 다르다. | 없음 |
파라미터 | 특정 스킴들에서 입력 파라미터를 기술하는 용도로 사용한다. 파라미터는 이름/값을 쌍으로 가진다. 파라미터는, 다른 파라미터나 경로의 일부와 세미콜론(;)으로 구분하여 기술하며, 여러개를 가질 수 있다. | 없음 |
질의 | 스킴에서 애플리케이션에 파라미터를 전달하는데 쓰인다. 질의 컴포넌트를 작성하는데 쓰이는 공통 포맷은 없다. 이는 URL의 끝에 “?”로 구분한다. | 없음 |
프래그먼트 | 리소스의 조각이나 일부분을 가리키는 이름이다. URL이 특정 객체를 가리킬 경우에 프래그먼트 필드는 서버에 전달되지 안흔ㄴ다. 이는 클라이언트에서만 사용한다. URL의 끝에서 “#”문자로 구분한다. | 없음 |
2.2.1 스킴 : 사용할 프로토콜
- 주어진 리소스에 어떻게 접근할지 나타냄
- 알파벳으로 시작해야 하고 나머지 부분들과 첫번째 “:”로 구분하며 대소문자를 구분하지 않는다.
2.2.2 호스트와 포트
- 리소스를 호스팅하고 있는 장비와 그 장비 내에서 리소스에 접근할 수 있는 서버가 어디인지를 가리킨다.
- 호스트 컴포넌트는 접근하려고 하는 리소스를 가지고 있는 인터넷상의 호스트 장비를 가리킨다.
- 호스트 명이 될 수도 있고, IP주소가 될 수도 있다.
- 포트 컴포넌트는 서버가 열어놓은 네트워크 포트를 가리킨다.
2.2.3 사용자 이름과 비밀번호
- FTP 서버 등에서는 데이터에 접근을 허용하기 전에 사용자 이름과 비밀번호를 요구한다.
2.2.4 경로
- URL의 경로 컴포넌트는 리소스가 서버의 어디에 있는지 표기한다.
- 유닉스 파일 시스템의 파일 경로와 유사하게 ‘/’문자를 기준으로 경로 조각으로 나뉜다.
2.2.5 파라미터
- 많은 프로토콜은 리소스에 접근하기 위해 사용자 이름과 비밀번호 뿐 아니라 더 많은 정보를 요구한다.
- 파라미터 컴포넌트는 애플리케이션이 서버에 정확한 요청을 하기 위해 필요한 입력 파라미터를 받는데 사용한다.
- 이름/값 쌍의 리스트들로 ‘;’문자로 구분하여 기술한다.
2.2.6 질의 문자열
- 데이터베이스 같은 서버들은 요청받을 리소스 형식의 범위를 좁히기 위해서 질문이나 질의를 받을 수 있다.
http://www.joes-hardware.com/inventory-check.cgi?item=12731&color=blue&size=large
- 위 질의는 제푸번호가 12731이고, 큰 치수에, 파란색인 물품의 재고가 있는지 검사한다.
2.2.7 프래그먼트
- 프래그먼트 컴포넌트를 통해 리소스 내의 조각을 가리킬 수 있다.
- 일반적으로 HTTP 서버는 객체 일부가 아닌 전체만 다루기 때문에, 클라이언트는 서버에 프래그먼트를 전달하지 않고 브라우저가 서버로부터 전체 리소스를 내려받은 후 프래그먼트를 사용하여 리소스의 일부를 보여준다.
2.3 단축 URL
2.3.1 상대 URL
./hammers.html
- 절대 URL과 달리 상대 URL은 모든 정보를 담고 있지 않다.
- 리소스에 접근하기 위해 필요한 모든 정보를 얻기 위해서는
기저
라고 하는 다른 URL을 사용해야 한다.- 상대 URL을 사용하면 리소스 집합을 쉽게 변경할 수 있다.
- 문서 집합의 위치를 변경하더라도, 새로운 기저 URL에 의해 해석되므로 정상적으로 동작한다.
2.3.2 URL 확장
- 호스트 명 확장
- 단순한 휴리스틱만을 사용해서 입력한 호스트 명을 전체 호스트 명으로 확장한다.
- 주소란에
yahoo
를 입력하면 브라우저는 자동으로www.
와.com
을 붙여www.yahoo.com
을 만든다. - 사용자의 시간을 절약하고 혼란을 막는다.
- 히스토리 확장
- 브라우저는 과거에 사용자가 방문했던 URL의 기록을 저장한다.
- URL을 입력하면 입력된 URL의 앞 글자들을 포함하는 완결된 형태의 URL들을 선택하게 해준다.
2.4 안전하지 않은 문자
- 안전한 전송이란 정보가 유실될 위험 없이 URL을 전송할 수 있다는 것을 의미한다.
- URL은 상대적으로 작고 일반적으로 안전한 알파벳 문자만 포함하도록 허락한다.
- 사람들이 URL에 이진 데이터나 일반적으로 안전한 알파벳 외에 문자도 포함하려고 할 때가 있다는 것을 알고 이스케이프 기능을 추가하여 안전하지 않은 문자를 안전한 문자로 인코딩할 수 있게 했다.
2.4.1 URL 문자 집합
- 많은 애플리케이션이 7비트로 이루어진 US-ASCII 문자 집합을 사용하나, 이는 굉장히 적은 문자만 포함한다(영어).
- 뿐 아니라 URL이 특정 이진 데이터를 포함해야 하는 경우도 있으므로 설계자들은 URL에 이스케이프 문자열을 쓸 수 있도록 설계했다.
2.4.2 인코딩 체계
- 몇몇 안전하지 않은 문자들을 표현할 수 있는 인코딩 방식을 고안했다.
- 안전하지 않은 문자를 퍼센티지 기호로 시작해 두개의 16진수 숫자로 이루어진 이스케이프문자로 바꾼다.
문자 | ASCII 코드 | URL 예 |
---|---|---|
~ | 126 (0x7E) | http://www.joes-hardware.com/%7Ejoe |
빈 문자 | 32 (0x20) | http://www.joes-hardware.com/more%20tools.html |
% | 37 (0x25) | http://www.joes-hardware.com/100%25satisfaction.html |
2.4.3 문자 제한
- 몇몇 문자는 URL 내에서 특별한 의미로 사용되고, US-ASCII의 출력 가능한 문자 집합에 포함되어 있지 않고, 몇몇 인터넷 게이트웨이와 프로토콜에서 혼동되는 것으로 알려져 있어 사용이 꺼려지기도 한다.
- 이러한 예약된 문자들을 본래 목적이 아닌 다른 용도로 사용하려면 반드시 인코딩해야 한다.
- 예) % / . .. # ? ; : 등
2.4.4 좀더 알아보기
- 안전하지 않은 문자를 그대로 사용해도 문제가 발생하지 않을 순 있지만, 혼동의 여지가 있기 때문에 모두 변환해야 한다.
- 어떤 문자를 인코딩해야 하는가는 브라우저와 같이 최초로 URL을 입력받는 애플리케이션에서 하는 것이 적절하다.
- 모든 문자를 인코딩하는 방법도 있으나, 선호되지 않는다.
2.6 미래
- URL은 주소이지 실제 이름이 아니므로 완벽하지 않다. 리소스가 옮겨지면 더는 사용할 수 없다.
- 이상적인 방법은 그 객체를 가리키는 실제 객체의 이름을 사용하는 것이다. -> URN
- URL에서 URN으로 주소 체계를 바꾸는 것은 매우 큰 작업이다. 이러한 전환을 위해서는 굉장히 많은 시간이 걸릴 것이다.
3장 HTTP 메시지
3.1 메세지의 흐름
- 인바운드 : 클라이언트 -> 프록시 -> 서버 방향
- 아웃바운드 : 서버 -> 프록시 -> 클라이언트 방향
- 업스트림 / 다운스트림 : 발송지에 가까울수록 업스트림, 수신지에 가까울수록 아웃스트림
3.2 메세지의 각 부분
- 메세지는 시작줄, 헤더 블록, 본문으로 나누어진다.
- 시작줄 및 헤더와 달리 본문은 비어있을 수도 있다.
3.2.1 메세지 문법
- 메서드
- 클라이언트 측에서 서버가 리소스에 대해 수행해주길 바라는 동작.
GET
,HEAD
,POST
등
- 요청 URL
- 요청 대상이 되는 리소스를 지칭하는 완전한 URL 혹은 URL의 경로 구성요소
- 버전
- HTTP/<메이저>.<마이너> 의 형태마이너>메이저>
- 메이저, 마이너는 모두 정수
- 상태 코드
- 요청 중에 무엇이 일어났는지 설명하는 세자리 숫자
- 각 코드의 첫번째 자릿수는 일반적인 분류를 나타낸다.
- 사유 구절
- 상태 코드를 사람이 이해할 수 있게 설명해주는 문구
- 사유 구절이 직접적으로 처리과정에 영향을 미치진 않는다.
- 헤더
- 0개 이상의 헤더를 나열할 수 있다.
- 모든 헤더를 기입하면 빈줄(CRLF)을 통해 헤더가 끝났음을 알린다. (본문이 없더라도)
- 엔티티 본문
- 모든 메시지가 엔티티 본문을 갖지는 않는다.
3.2.2 시작줄
요청줄
- 메서드 + 리소스URL + HTTP버전으로 구성
- 메서드
- 메서드의 종류
- 모든서버가 모든 메서드를 구현하고 있는 것은 아니다.
응답줄
- HTTP버전 + 상태코드 + 사유구절로 구성
- 상태 코드
- 상태코드의 종류
- 서버가 클라이언트에게 무엇이 일어났는지 말해준다.
- 사유구절
- 표준은 있으나 엄격한 규칙은 없다.
- HTTP 버전 번호
- 1.1버전과 통신하는 1.2버전은 1.2버전의 새 기능을 사용할 수 없다. (낮은 쪽에 맞추어 통신)
- 해당 애플리케이션이 지원하는 가장 높은 HTTP 버전을 가리킨다.
- HTTP/1.1이라고 보냈다면, 1.1버전으로 통신한것이라는 뜻이 아닌 1.1버전까지 수신할 수 있음을 표시
- 버전번호는 소숫점단위가 아니다. 즉 HTTP/1.22버전은 HTTP/1.3버전보다 높다.
3.2.3 헤더
- 일반 헤더 : 요청과 응답 양쪽에 모두 나타날 수 있음
- 요청 헤더 : 요청에 대한 부가 정보를 제공
- 응답 헤더 : 응답에 대한 부가 정보를 제공
- 엔티티 헤더 : 본문 크기와 콘텐츠, 혹은 리소스 그 자체를 서술
- 확장 헤더 : 명세에 정의되지 않은 새로운 헤더
- 헤더가 길다면 줄을 나눌 수 있다. 단 추가줄 앞에 최소 하나의 스페이스 혹은 탭 문자가 와야 한다.
3.2.4 엔티티 본문
- 이미지, 비디오, 신용카드 트랜잭션 등 여러 종류의 데이터를 실어나를 수 있다.
3.3 메서드
3.3.1 안전한 메서드
- GET, HEAD 등 요청을 보내도 서버에 어떠한 변화도 주지 않는 메서드
3.3.2 GET
- 서버에게 리소스를 달라고 요청할 때 주로 사용한다.
GET /seasonal/index-fall.html HTTP/1.1
Host: www.joes-hardware.com
Accept: *
3.3.3 HEAD
- GET과 똑같이 행동하지만, 헤더만을 반환받는다.
- 사용 이유
- 리소스를 가져오지 않고도 리소스에 대한 정보를 알 수 있다.
- 응답의 상태 코드를 통해 개체의 존재여부를 알 수 있다.
- 헤더를 확인하여 리소스의 변경여부를 알 수 있다.
// 요청메세지
HEAD / seasonal/index-fall.html HTTP/1.1
Host: www.joes-hardware.com
Accept: *
// 응답메세지
HTTP/1.1 200 OK
Content-Type: text/html
Context-Length: 617
3.3.4 PUT
- PUT으로 요청하면 서버는 요청의 본문을 가지고 요청 URL의 이름대로 새 문서를 만들거나, 이미 있다면 대체한다.
PUT /product-list.txt HTTP/1.1
Host: www.joes-hardware.com
Content-type: text/plain
Content-length: 34
Updated product list coming soon!
3.3.5 POST
- 서버에 입력 데이터를 전송하기 위해 설계되었다.
- HTML폼을 지원하기 위해 흔히 사용되고 이는 서버로 전송되어진다.
POST /inventory-check.cgi HTTP/1.1
Host: www.joes-hardware.com
Content-type: text/plain
Content-length: 18
item=bandsaw 2647 // HTML폼이 사용자에 의해 채워진 내용
3.3.6 TRACE
- 요청은 프록시, 게이트웨이, 방화벽등을 통과하게 되고 이들은 HTTP 요청을 수정할 수 있다.
- TRACE메서드는 이러한 애플리케이션들을 거쳐서 최종적으로 서버에 도달했을때의 모습을 알고싶을 때 사용한다.
- 요청이 의도된대로 흘러가는지를 확인하는 등 진달을 위하여 주로 사용된다.
- 많은 HTTP 애플리케이션은 메서드에 따라 다르게 동작하는데, TRACE는 이러한 점을 고려할 수 없다는 문제가 있다.
// 요청 메세지(클라이언트 -> 프록시)
TRACE /product-list.txt HTTP/1.1
Accpt: *
Host: www.joes-hardware.com
// 요청 메세지(프록시 -> 서버)
TRACE /product-list.txt HTTP/1.1
Accpt: *
Host: www.joes-hardware.com
Via: 1.1 proxy3.company.com
// 응답 메세지(서버 -> 프록시)
HTTP/1.1 200 OK
Content-type: text/plain
Content-length: 96
TRACE /product-list.txt HTTP/1.1
Accpt: *
Host: www.joes-hardware.com
Via: 1.1 proxy3.company.com
// 응답 메세지(프록시 -> 클라이언트)
HTTP/1.1 200 OK
Content-type: text/plain
Content-length: 96
Via: 1.1 proxy3.company.com
TRACE /product-list.txt HTTP/1.1
Accpt: *
Host: www.joes-hardware.com
Via: 1.1 proxy3.company.com
3.3.7 OPTIONS
- 웹 서버에게 특정 리소스에 대해 어떤 메서드가 지원되는 지를 물어본다.
// 요청메세지
OPTIONS * HTTP/1.1
Host: www.joes-hardware.com
Accept: *
// 응답 메세지
HTTP/1.1 200 OK
Allow: GET, POST, PUT, OPTIONS
Context-length: 0
3.3.8 DELETE
- 서버에게 요청 URL로 지정한 리소스를 삭제할 것을 요청한다.
- 서버는 이를 무시할 수 있다. 따라서 클라이언트는 삭제의 수행을 보장받지 못한다.
DELETE /product-list.txt HTTP/1.1
Host: www.joes-hardware.com
3.3.9 확장메서드
- HTTP는 필요에 따라 메서드를 확장해도 상관없도록 설계되어 있다.
- 명세에는 정의되어있지 않으나 수많은 메서드들이 존재한다.
3.4 상태 코드
3.4.1 100-199: 정보성 상태 코드
- 작업의 최적화를 위한 의도로 도입되었으나 잘 사용되지 않는다.
3.4.2 200-299: 성공 상태 코드
- 성공을 의미하는 상태 코드
- 성공 상태 코드의 종류
3.4.3 300-399: 리다이렉션 상태 코드
- 클라이언트가 관심있어 하는 리소스에 대해 다른 위치를 사용하라고 말해주거나 리소스의 내용 대신 다른 대안 응답을 제공한다.
Location
헤더를 통하여 리소스가 옮겨졌다면 어느 위치로 옮겨졌는지 전달할 수 있다.- 리다이렉션 상태 코드의 종류
3.4.4 400-499: 클라이언트 에러 상태 코드
- 존재하지 않는 URL에 대한 요청 등 잘못 구성된 요청 메세지들에 대한 응답이다.
- 클라이언트 에러 상태 코드의 종류
3.4.5 500-599: 서버 에러 상태 코드
- 올바른 요청을 보냈음에도 서버 자체에서 에러가 발생할 수 있다.
- 서버 에러 상태 코드의 종류
3.5 헤더
3.5.1 일반 헤더
- 메세지에 대한 기본 정보를 제공한다.
헤더 | 설명 |
---|---|
Connection | 클라이언트와 서버가 요청/응답 연결에 대한 옵션을 정할 수 있게 해준다. |
Date | 메세지가 언제 만들어졌는지에 대한 날짜와 시간을 제공한다. |
MIME-Version | 발송자가 사용한 MIME의 버전을 알려준다. |
Trailer chunked transfer | 인코딩으로 인코딩된 메세지의 끝 부분에 위치한 헤더들의 목록을 나열한다. |
Transfer-Encoding | 수신자에게 안전한 전송을 위해 메세지의 어떤 인코딩이 적용되었는지 말해준다. |
Upgrade | 발송자가 ‘업그레이드’하길 원하는 새 버전이나 프로토콜을 알려준다. |
Via | 이 메세지가 어떤 중개자(프록시, 게이트웨이)를 거쳐 왔는지 보여준다. |
- 일반 캐시 헤더
- 매번 원 서버로부터 객체를 가져오는 대신 로컬 복사본으로 캐시할 수 있다.
헤더 | 설명 |
---|---|
Cache-Control | 메세지와 함께 캐시 지시자를 전달하기 위해 사용한다. |
Pragma | 메세지와 함께 지시자를 전달하는 또 다른 방법. 캐시에 국한되지 않는다. |
- 현재 Pragma는 Cache-Control로 인해 더이상 사용되지 않을 예정이다.
3.5.2 요청 헤더
- 요청에서만 의미를 갖는 헤더
- 누가, 무엇이 그 요청을 보냈는지에 대한 정보나 클라이언트의 선호나 능력에 대한 정보를 준다.
헤더 | 설명 |
---|---|
Client-IP | 클라이언트가 실행된 컴퓨터의 IP를 제공한다. |
From | 클라이언트 사용자의 메일 주소를 제공한다. |
Host | 요청의 대상이 되는 서버의 호스트 명과 포트를 준다. |
Referer | 현재의 요청 URI가 들어있었던 문서의 URL을 제공한다. |
User-Agent | 요청을 보낸 애플리케이션의 이름을 서버에게 말해준다. |
- Accept 관련 헤더
- 클라이언트는 Accept 관련 헤더들로 서버에게 자신의 선호와 능력을 알려줄 수 있다.
- 서버는 이 정보를 통해 무엇을 보낼 것인가에 대해 더 똑똑한 결정을 내릴 수 있다.
- 많은 시간과 대역폭 낭비를 막을 수 있다.
헤더 | 설명 |
---|---|
Accept | 서버에게 서버가 보내도 되는 미디어 종류를 말해준다. |
Accept-Charset | 서버에게 서버가 보내도 되는 문자집합을 말해준다. |
Accept-Encording | 서버에게 서버가 보내도 되는 인코딩을 말해준다. |
Accept-Language | 서버에게 서버가 보내도 되는 언어를 말해준다. |
TE | 서버에게 서버가 보내도 되는 확장 전송 코딩을 말해준다. |
- 조건부 요청 헤더
- 특정 조건에 맞추어 응답을 요청할 수 있다.
헤더 | 설명 |
---|---|
Expect | 클라이언트가 요청에 필요한 서버의 행동을 열거할 수 있게 해준다. |
If-Match | 문서의 엔티티 태그가 주어진 엔티티 태그와 일치하는 경우에만 문서를 가져온다. (7장) |
If-Modified-Since | 주어진 날짜 이후에 리소스가 변경되지 않았다면 요청을 제한한다. |
If-None-Match | 문서의 엔티티 태그가 주어진 엔티티 태그와 일치하지 않는 경우에만 문서를 가져온다. |
If-Range | 문서의 특정 범위에 대한 요청을 할 수 있게 해준다. |
If-Unmodified-Since | 주어진 날짜 이후에 리소스가 변경되었다면 요청을 제한한다. |
Range | 서버가 범위 요청을 지웒나다면, 리소스에 대한 특정 범위를 요청한다. |
- 요청 보안 헤더
- 보안에 대해서는 14장에서 자세히 다룬다.
- 쿠키에 대해서는 11장에서 자세히 다룬다.
헤더 | 설명 |
---|---|
Authorization | 클라이언트가 서버에게 제공하는 인증 그 자체에 대한 정보를 담고 있다. |
Cookie | 클라이언트가 서버에게 토큰을 전달할 때 사용한다. 진짜 보안 헤더는 아니지만, 보안에 영향을 줄 수 있다. |
Cookie2 | 요청자가 지원하는 쿠키의 버전을 알려줄 떄 사용한다. |
- 프록시 요청 헤더
- 프록시에 대해서는 6장에서 자세히 다룬다.
헤더 | 설명 |
---|---|
Max-Forwards | 요청이 원 서버로 향하는 과정에서 다른 프록시나 게이트웨이로 전달될 수 있는 최대 횟수 |
Proxy-Authorization | Authorization과 같으나 프록시에서 인증을 할 때 쓰인다. |
Proxy-Connection | Connection과 같으나 프록시에서 연결을 맺을 때 쓰인다. |
3.5.3 응답 헤더
- 응답 헤더는 클라이언트에게 부가 정보를 제공한다.
- 클라이언트가 응답을 잘 다루고 나중에 더 나은 요청을 할 수 있도록 도와준다.
헤더 | 설명 |
---|---|
Age | 응답이 얼마나 오래되었는지 |
Public | 서버가 특정 리소스에 대해 지원하는 요청 메서드의 목록 |
Retry-After | 현재 리소스가 사용 불가능한 상태일 때, 언제 가능해지는지 날짜 혹은 시간 |
Server | 서버 애플리케이션의 이름과 버전 |
Title | HTML 문서에서 주어진 것과 같은 제목 |
Warning | 사유 구절에 있는 것보다 더 자세한 경고 메세지 |
- 협상 헤더
- 협상에 대해서는 17장에서 자세히 다룬다.
헤더 | 설명 |
---|---|
Accept-Ranges | 서버가 자원에 대해 받아들일 수 있는 범위의 형태 |
ary | 서버가 확인해 보아야 하고 그렇기 때문에 응답에 영향을 줄 수 있는 헤더들의 목록 |
- 응답 보안 헤더
- 보안에 대해서는 14장에서 자세히 다룬다.
헤더 | 설명 |
---|---|
Proxy-Authenticate | 프라깃에서 클라이언트로 보낸 인증요구의 목록 |
Set-Cookie | 진짜 보안 헤더는 아니지만, 보안에 영향을 줄 수 있다. 서버가 클라이언트를 인증할 수 있도록 클라이언트 측에 토큰을 설정하기 위해 사용한다. |
Set-Cookie2 | Set-Cookie와 비슷하게 RFC 2965로 정의된 쿠키 |
WWW-Authenticate | 서버에서 클라이언트로 보낸 인증요구의 목록 |
3.5.4 엔티티 헤더
- 엔티티에 대해 설명하는 헤더
- 개체 타입, 요청할 수 있는 유효 메서드 등 광범위한 정보 제공
헤더 | 설명 |
---|---|
Allow | 이 엔티티에 대해 수행될 수 있는 요청 메서드들을 나열 |
Location | 클라이언트에게 엔티티가 실제로 어디에 위치하고 있는지 말해준다. 수신자에게 리소스에 대한 위치를 알려줄 때 사용한다. |
- 콘텐츠 헤더
- 엔티티의 콘텐츠에 대한 구체적인 정보를 제공
- 종류, 크기, 기타 콘텐츠를 처리할 떄 유용하게 활용될 수 있는 것들
헤더 | 설명 |
---|---|
Content-Base | 본문에서 사용된 상대 URL을 계산하기 위한 기저 URL |
Content-Encoding | 본문에 적용된 어떤 인코딩 |
Content-Language | 본문을 이해하는데 가장 적절한 자연어 |
Content-Length | 본문의 길이나 크기 |
Content-Location | 리소스가 실제로 어디에 위치하는지 |
Content-MD5 | 본문의 MD5 체크섬 |
COntent-Range | 전체 리소스에서 이 엔티티가 해당하는 범위를 바이트 단위로 표현 |
COntent-Type | 이 본문이 어떤 종류의 객체인지 |
- 엔티티 캐싱 헤더
- 엔티티 캐싱에 대한 정보를 제공
- 리소스에 대해 캐시된 사본이 아직 유효한지에 대한 정보, 캐시된 리소스가 더이상 유효하지 않게 되는 시점 등
헤더 | 설명 |
---|---|
ETag | 이 엔티티에 대한 엔티티 태그 |
Expires | 이 엔티티가 더 이상 유효하지 않아 원본을 다시 받아와야 하는 일시 |
Last-Modified | 가장 최근 이 엔티티가 변경된 일시 |
4장 커넥션 관리
4.1 TCP 커넥션
- 서버와 클라이언트는 TCP/IP 커넥션을 맺으며 일단 커넥션이 맺어지면 주고받는 메세지들은 손실 혹은 손상되거나 순서가 바뀌지 않고 안전하게 전달된다.
4.1.1 신뢰할 수 있는 데이터 전송 통로인 TCP
- HTTP커넥션은 몇몇 사용 규칙을 제외하고는 TCP 커넥션에 불과하다.
4.1.2 TCP 스트림은 세그먼트로 나뉘어 IP 패킷을 통해 전송된다
- HTTP메세지를 전송할 때, TCP는 세그먼트라는 단위로 데이터 스트림을 잘게 나누고, 세그먼트를 IP패킷에 담아서 인터넷을 통해 전달한다.
- IP패킷의 구성요소
- IP 패킷 헤더 : 발신지와 목적지 IP 주소, 크기, 기타 플래그
- TCP 세그먼트 헤더 : TCP 포트 번호, TCP 제어 플래그, 데이터의 순서와 무결성을 검사할 때 사용되는 숫자값
- TCP 데이터 조각
4.1.3 TCP 커넥션 유지하기
- TCP커넥션은
발신지 IP 주소
,발신지 포트
,수신지 IP 주소
,수신지 포트
네가지 값으로 식별하며 이는 유일하다.
4.1.4 TCP 소켓 프로그래밍
- 운영체제는 TCP 커넥션의 생성과 관련된 소켓 API를 제공한다.
- 소켓 API를 사용하면, TCP 종단 데이터 구조를 생성하고, 원격 서버의 TCP 종단에 그 종단 데이터 구조를 연결하여 데이터 스트림을 읽고 쓸 수 있다.
4.2 TCP의 성능에 대한 고려
4.2.1 HTTP 트랜잭션 지연
- 실제 트랜잭션을 처리하는 시간은 TCP커넥션을 설정하고, 요청을 보내고 응답을 받는 시간에 비해 매우 짧다.
- 즉 HTTP 지연은 대부분 TCP 네트워크 지연 떄문에 발생한다.
- HTTP 트랜잭션을 지연시키는 원인
- (1) DNS로부터 URI에 있는 호스트명을 IP로 변환하는데에 시간이 걸린다. (현재는 인프라의 발전으로 굉장히 적은시간이 소요된다.)
- (2) 새로운 TCP 커넥션마다 커넥션 설정 시간이 소요된다.
- (3) 요청 메세지가 인터넷을 통해 서버로 전달되고 처리되는 과정에서 시간이 소요된다.
- (4) 웹 서버가 HTTP 응답을 보내는 과정에서 시간이 소요된다.
4.2.3 TCP 커넥션 핸드쉐이크 지연
- TCP 커넥션을 위해
3-way handshake
과정에 있어서 시간이 소요된다. 3-way handshake
의 순서- (1) 클라이언트는 작은 TCP 패킷을 서버에게 보내고, 그 패킷은
SYN
이라는 특별한 플래그를 가진다. 이는 커넥션 생성 요청이라는 뜻이다. - (2) 서버가 커넥션을 받으면 몇 가지 커넥션 매개변수를 산출하고 커넥션 요청이 받아들여졌음을 의미하ㅎ는
SYN
과ACK
플래그를 포함한 TCP 패킷을 보낸다. - (3) 클라이언트는 커넥션이 잘 맺어졌음을 알리는
ACK
플래그를 포함한 TCP 패킷을 서버에 보낸다.
- (1) 클라이언트는 작은 TCP 패킷을 서버에게 보내고, 그 패킷은
- 크기가 작은 HTTP 트랜잭션은 이러한 TCP를 설정하는데에 많은 시간을 소요한다.
4.2.4 확인응답 지연
- 인터넷은 패킷 전송을 완벽보장하지 않으므로, TCP가 자체적인 확인 체계를 가진다.
- 각 TCP 세그먼트는 순번과 데이터 무결성 체크섬을 가진다.
- 세그먼트 수신자는 세그먼트를 온전히 받으면 작은 확인응답 패킷을 송신자에게 반환한다.
- 송신자는 이를 수신하지 못한다면 패킷이 파기되었거나 오류가 있다고 판단하고 재전송한다.
- 확인응답 패킷은 크기가 작으므로 다른 TCP 패킷에 편승시켜 묶음으로써 더 네트워크를 효율적으로 사용한다.
- 보통 0.1~0.2초정도의 시간동안 저장해두는데, 그 안에 편승시킬 데이터를 찾지 못한다면 확인응답끼리 묶어서 별도의 패킷으로 전송한다.
- 하지만 정작 확인 응답이 편승할 데이터가 많이 발생하지 않으면 이러한 확인응답 지연 알고리즘으로 인한 지연이 자주 발생한다.
4.2.5 TCP 느린 시작(slow start)
- TCP 커넥션은 최초에는 최대 속도를 제한하고 데이터가 성공적으로 전송됨에 따라서 속도제한을 점점 높여나간다 -> TCP 느린 시작
- 인터넷의 급작스러운 부하와 혼잡을 방지한다.
- 따라서 새로운 커넥션은 이미 어느정도 데이터를 주고 받은 튜닝된 커넥션보다 느리다.
4.2.6 네이글(Nagle) 알고리즘과 TCP_NODELAY
- TCP 세그먼트는 40바이트 상당의 플래그와 헤더를 포함하기 때문에, TCP가 작은 크기의 데이터를 많이 전송할수록 네트워크 성능은 떨어진다.
- 존 네이글이 만든 알고리즘으로, 많은 양의 TCP 데이터를 한 개의 덩어리로 합쳐 전송한다.
- 다른 모든 패킷이 확인 응답을 받았을 경우를 제외하고는 세그먼트가 최대크기가 되지 않으면 전송하지 않는다.
- 확인 응답을 기다리던 패킷이 확인 응답을 받았거나 전송하기 충분한 만큼의 패킷이 쌓이면 버퍼에 있던 데이터가 전송된다.
- 문제점
- (1) 크기가 작은 HTTP메세지는 패킷을 채우기 못하기 때문에 생길지 모르는 데이터를 기다리며 지연된다.
- (2) 확인응답 지연과 함께 쓰이면 형편없이 동작한다. 네이글 알고리즘은 확인응답을 기다리는데, 정작 확인응답은 확인응답 지연 알고리즘에 의해 지연된다.
4.3 HTTP 커넥션 관리
4.3.1 흔히 잘못 이해하는 Connection 헤더
- 클라이언트와 서버사이에는 수많은 중개서버가 놓이는데, 어떤 경우에는 두 인접한 HTTP 애플리케이션이 맺고 있는 커넥션에만 적용될 옵션을 지정해야 할 때가 있다.
- Connection 헤더에 전달될 수 있는 토큰
- (1) HTTP 헤더 필드 명 : 이 커넥션에만 해당되는 헤더들을 나열
- (2) 임시적인 토큰 값 : 커넥션에 대한 비표준 옵션
- (3) close : 커넥션이 작업이 완려되면 종료되어야 함을 의미
- 처음 전달받은 프록시는 요청에 대한 모든 옵션을 적용하고 Connection 헤더와 Connection에 기술된 모든 헤더를 삭제하고 보낸다.
4.3.2 순차적인 트랜잭션 처리에 의한 지연
- 각 트랜잭션이 새로운 커넥션을 필요로 한다면 커넥션을 맺는데 발생하는 지연 및 느린 시작 지연이 발생한다.
- 순차적으로 로드하는 방식은 객체를 화면에 배치하려면 객체의 크기를 알아야 하기 때문에 모든 객체를 받기 전까지 텅 빈 화면을 보여준다.
- 이러한 점을 해결하기 위한 최신 기술들이 사용되고 있다.
4.4 병렬 커넥션
- HTTP는 클라이언트가 여러 개의 커넥션을 맺음으로써 여러 개의 HTTP 트랜잭션을 병렬로 처리할 수 있게 한다.
4.4.2 병렬 커넥션이 항상 더 빠르지는 않다
- 클라이언트의 네트워크의 대역폭이 좁을 때는 대부분의 시간을 데이터를 전송하는데에 쓰고, 결과적으로 병렬의 이점이 거의 없어진다.
- 웹페이지는 수십에서 수백개의 객체를 포함하는데, 이를 모두 병렬로 처리한다면 많은 메모리를 필요로한다.
- 현재는 대부분 6~8개의 병렬 커넥션을 지원한다.
4.5 지속 커넥션
- HTTP 요청을 하기 시작한 애플리케이션은 웹 페이지 내의 다른 이미지 등을 가져오기 위해서 그 서버에 또 요청하는 일이 잦다. 이를 사이트 지역성이라 부른다.
HTTP/1.1
부터는 TCP 커넥션을 유지하여 앞으로 있을 HTTP 요청에 재사용할 수 있다.- 커넥션을 맺기 위한 준비작업에 따르는 시간을 절약할 수 있다.
4.5.1 지속 커넥션 vs 병렬 커넥션
- 병렬 커넥션에는 몇가지 단점이 있다.
- (1) 각 트랜잭션마다 새로운 커넥션을 맺고 끊기 때문에 시간과 대역폭이 소요된다.
- (2) 각각의 새로운 커넥션은 TCP 느린 시작 때문에 성능이 떨어진다.
- (3) 실제로 연결할 수 있는 병렬 커넥션의 수에는 제한이 있다.
- 지속커넥션은 위의 단점을 보완하지만 관리를 잘못할 경우 수많은 커넥션이 연결상태로 유지되어 불필요한 소모를 발생시킨다.
- 지속 커넥션은 병렬 커넥션과 함께 사용하면 더욱 효과적이다.
4.5.8 HTTP/1.1의 지속 커넥션
- HTTP/1.1의 지속 커넥션은 HTTP/1.0의 keep-alive 커넥션과 달리 기본으로 활성화되어 있다.
- 커넥션을 끊으려면
Connection: close
헤더를 명시해야 한다. - 하지만
Connection: close
를 보내지 않더라도 서버와 클라이언트는 언제든지 커넥션을 끊을 수 있다.
4.6 파이프라인 커넥션
- HTTP/1.1은 지속 커넥션을 통해서 요청을 파이프라이닝할 수 있다.
- 여러 개의 요청은 응답이 도착학히 전까지 큐에 쌓인다.
- 제약사항
- 클라이언트는 커넥션이 지속 커넥션인지 확인하기 전까지는 파이프라인을 이어서는 안 된다.
- 응답은 요청 순서와 같게 와야 한다.
- 클라이언트는 언제 커넥션이 끊어지더라도 완료되지 않은 요청이 파이프라인에 있으면 언제든지 다시 보낼 준비가 되어 있어야 한다.
- POST와 같은 비멱등 요청을 재차 보내면 문제가 생길 수 있기 때문에 파이프라인을 통해 보내면 안된다.
4.7 커넥션 끊기
4.7.1 ‘마음대로’ 커넥션 끊기
- 서버, 프록시, 클라이언트는 언제든 커넥션을 끊을 수 있다.
4.7.2 Content-Length와 Truncation
- 각 HTTP 응답은 본문의 정확한 크기 값을 가지는
Content-Length
헤더를 가져야 한다. - 커넥션이 끊어졌다는 HTTP 응답을 받은 후, 실제 전달된 엔티티의 길이와 헤더값이 일치하지 않거나 존재하지 않으면 다시 서버에게 물어봐야 한다.
- 수신자가 캐시 프록시라면 응답을 캐시해서는 안된다. 프록시는
Content-Length
를 정정하려 하지 말고 그대로 전달해야 한다.
4.7.3 커넥션 끊기의 허용, 재시도, 멱등성
- 예상치 못하게 커넥션이 끊어졌을 때에 적절히 대응할 준비가 되어있어야 한다.
- 어떤 요청데이터가 전송되었지만, 응답이 오기 전에 커넥션이 끊기면 클라이언트는 실제로 서버에서 얼만큼 요청이 처리되었는지 알 수 없다.
GET
,HEAD
,PUT
,DELETE
,TRACE
,OPTIONS
메서드와 같은 멱등 메서드만이 파이프라인을 통해 요청해야 한다.
4.7.4 우아한 커넥션 끊기
- TCP 커넥션은 양방향이다.
- 전체 끊기 : 입력채널과 출력채널을 모두 끊는다.
- 절반 끊기 : 입력채널과 출력채널 중 하나만 끊을 수 있다.
- 예상치 못한 에러를 예방하기 위해서는
절반 끊기
를 사용해야 한다. (출력부터 끊는 것이 안전하다.) - 클라이언트가 더이상 데이터를 보내지 않는다는 확신이 없는 이상 커넥션의 입력 채널을 끊는 것은 위험하다.
Leave a comment