다른 여러 네트워크 프로토콜들과 마찬가지로 HTTP 역시 클라이언트-서버 모델을 가지고 있습니다. HTTP클라이언트는 서버로 향하는 컨넥션을 만들고 리퀘스트 메시지(request message)를 보냅니다. 응답을 마친 서버는 컨넥션을 닫아 버립니다. HTTP 컨넥션에 대한 지속적인 상태를 유지하지 않습니다. 이런 프로토콜 성향 때문에 HTTP를 비상태유지(stateless)프로토콜이라고 합니다.
요청 메시지와 응답 메시지의 포멧은 비슷합니다. 둘 다 텍스트 기반의 프로토콜이며 아래와 같은 메시지 구조를 갖습니다 :
- 이니셜 라인(initial line)
- 이니셜 리퀘스트 라인과 이니셜 리스폰스 라인, 두 가지로 구분 됩니다.
- 헤더 라인
- 헤더라인 자체가 없어도 되고 1개 이상의 헤더라인이 와도 상관은 없습니다.
- header: value 형태로 구성 됩니다.
- 공백라인
- 헤더와 메시지 바디를 구분하는 아무 것도 없는 공백라인은 꼭 필요 합니다.
- 메시지 바디(message body)
- 메시지 바디는 필요에 따라서 사용해도 되고 사용하지 않아도 상관 없습니다.
보다 알아보기 쉽게 표현 하자면 아래와 같습니다 :
Header1: value1
Header2: value2
Header3: value3
<선택적으로 메시지 바디가 이곳에 오게 됩니다. 메시지 바디에는 데이터나 쿼리, $&*%!^$ 같은 바이너리 데이터 등이 올 수 있습니다>
이니셜 라인과 헤더는 반드시 CRLF로 끝을 맺어야 합니다. (보다 정확히 이야기 하자면 CR과 LF는 ASCII 코드의 13번과 10번 입니다)
Initial Request Line
리퀘스트를 위한 이니셜 라인과 리스폰스를 위한 이니셜 라인은 다릅니다. 이니셜 리퀘스트 라인은 스페이스 문자를 구분자로 하여 메소드 이름, 요청 되는 리소스의 로컬 패스, HTTP의 버젼 이렇게 세 부분으로 구성 되어 있습니다.
Notes:
- GET은 가장 일반적인 HTTP 메소드 입니다. 이 메소드는 "나에게 이 리소스를 주세요!" 라는 의미 입니다. 메소드의 이름은 항상 대문자로 쓰여야만 합니다. GET외에도 POST, HEAD 같은 메소드 들이 있습니다.
- 패스는 호스트 이름 다음에 오는 URL의 나머지 부분입니다. 이것은 request URI 라고도 불립니다.
- HTTP 버젼은 항상 "HTTP/x.x" 형태의 대문자여야 합니다The HEAD Method
HEAD 메소드
HEAD 메소드는 헤더에만 들어 있는 응답을 받는다는 것을 제외하면 GET 메소드와 비슷하다. 이 메소드는 요청하는 리소스의 정보를 체크하는데 유용하게 사용됩니다 :
- HEAD 리퀘스의 응답은 절대 메시지 바디를 가지지 않습니다. 다만 스테이터스 라인과 헤더 라인만을 가집니다.
POST 메소드
POST 메소드는 클라이언트에서 서버측으로 보내는 메시지가 서버측의 프로그램에 의해 어떤 처리가 되어져야 할 때 사용됩니다. 예를 들어 CGI 같은 것들이 있습니다. POST 메소드는 GET 메소드와는 아래와 같은 것들이 차이를 보이고 있습니다 :
- 리퀘스트와 함께 메시지 바디 안에 데이터 블록이 전송 됩니다. 메시지 바디를 전송하기 위해서 Content-Type: 와 Content-Length: 같은 헤더 라인이 추가 됩니다.
- 리퀘스트 URI는 요청하는 자원의 경로가 아니라 전송하는 데이터를 처리해 줄 프로그램의 경로를 가리킵니다.
- HTTP 응답은 고정된 파일이 아니라, 프로그램의 결과물입니다.
POST 메소드의 가장 일반적인 사용은 HTML의 form에서 CGI 스크립트로 submit을 할 경우입니다. 이 경우 Content-Type: 헤더는 주로 application/x-www-form-urlencoded로 셋팅되며, Content-Length: 는 URL형태로 인코딩된 데이터의 길이를 나타냅니다(note on URL-encoding). 이렇게 메시지를 전송하면 CGI는 STDIN으로 이 메시지들을 읽어들이고 디코딩 합니다 :
From: frog@jmarshall.com
User-Agent: HTTPTool/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 32
home=Cosby&favorite+flavor=flies
데이터가 무엇이건 간에 상관 없이, HTML의 submit form을 이용하는 것에 상관 없이, POST 메소드는 모든 데이터를 전송이 가능합니다. 단지 송신자와 수신자간의 미리 약속된 포멧만 지켜주면 됩니다. 그리고 GET메소드 역시 submit form을 이용해 전송하는 것이 가능합니다. 보다 자세한 사항은more details 를 보세요.
Initial Response Line (Status Line)
이니셜 리스폰스 라인은 스테이터스 라인(status line)이라고 도 불립니다. 그리고 이니셜 리스폰스 라인도 이니셜 리퀘스트 라인처럼 세 부분으로 나뉘어 있습니다만 내용은 다릅니다. 구성은 HTTP 버젼, 리퀘스트 결과에 대한 정보를 가리키는 리스폰스 스테이터스 코드(response status code), 그리고 리스폰스 스테이스터스 코드에 대한 영어로 된 설명(reason phrase) 입니다. 일반적으로 아래와 비슷한 형태 입니다 :
이거나
이지요.
Notes:
- HTTP버젼은 이니셜 리퀘스트 라인과 동일한 포멧인 "HTTP/x.x" 형태 입니다
- 스테이터스 코드는 컴퓨터가 읽는 코드 입니다. 사람이 읽기 편한 것은 그 뒤의 reason phrase 입니다.
- 스테이터스 코드는 3자리의 숫자로 되어 있습니다. 그리고 첫 번째 숫자는 각 결과의 카테고리를 구분하는 역할을 합니다 :
- 1xx 정보 메시지만 담고 있음을 의미합니다
- 2xx 특정 종류의 성공을 의미합니다
- 3xx redirects the client to another URL
- 4xx 클라이언트측의 에러를 의미합니다
- 5xx 서버측의 에러를 의미합니다.
일반적으로 가장 많이 사용되는 스테이터스 코드는 아래와 같습니다 :
- 200 OK
- 리퀘스트가 성공하고 결과 리소스가 메시지 바디에 들어 있음을 가리킵니다
- 404 Not Found
- 요청된 리소스가 없습니다
- 301 Moved Permanently
302 Moved Temporarily
303 See Other (HTTP 1.1 only)- 리소스가 다른 URL로 옮겨졌음을 의미 합니다.
- 500 Server Error
스테이터스 코드에 관련된 내용은 the HTTP specification (section 9 for HTTP 1.0, and section 10 for HTTP 1.1)을 참고 하시면 됩니다.
Header Lines
헤더 라인은 요청/응답 혹은 메시지에 실려 보내진 객체에 관련한 정보를 제공합니다.
헤더 라인의 포멧은 "Header-Name: value" 형식으로 되어 있고 CRLF(복귀와 개행문자)로 끝을 맺습니다. 이것은 RFC 822의 section 3에 정의 되어 있습니다 :
- 헤더라인은 복귀문자와 개행문자(CRLF, \r\n)로 끝나야만 합니다.
- 헤더의 이름은 대소문자 구분을 합니다(값도 아마 구분을 할 것입니다).
- ":" 와 값 사이에는 스페이스 문자나 탭 문자가 들어가야 합니다.
- 스페이스 문자나 탭 문자로 시작하는 헤더라인은 이전 헤드라인에 연속입니다. 가독성을 위해 이 방법을 이용해 긴 한 줄을 여러줄로 나눌 수 있습니다.
따라서 아래의 두 헤더는 동일 합니다 :
HEADER1: some-long-value-1a,
some-long-value-1b
HTTP 1.0은 16개의 해더를 정해 놓았습니다만, 반드시 사용해야 할 필요는 없습니다. HTTP 1.1은 46개의 헤더를 정했고 한가지(Host:)는 반드시 넣어 줘야만 합니다. 네티켓을 지킬줄 아는 당신이라면 이 헤더들을 추가 하는 것을 고려 해 보는 것도 좋습니다 :
- From: 헤더는 리퀘스트를 만든 사람의 이메일 주소를 기록합니다. 이 헤더는 사용자의 프라이버시를 위해 사용자가 선택적으로 기록할 수 있도록 해야만 합니
- User-Agent: 는 리퀘스트 메시지를 만든 프로그램을 구분하는 헤더입니다. "Program-name/x.xx"와 같은 형식이에서 x.xx라는 것은 대부분 버젼을 나타냅니다. 예를 들어서 Netscape 3.0 은 "User-agent: Mozilla/3.0Gold" 과 같은 헤더를 만들어 냅니다.
이와 같은 헤더들은 웹마스터들이 여러가지 문제를 해결하는데 도움을 주기도 하지만 사용자의 정보를 노출 하기도 합니다. 만일 메시지에 특정 헤더를 포함하기로 했다면 사용자의 프라이버시와 웹마스터의 로깅자료에 대해서 적절한 타협점을 찾아야 합니다.
만일 서버를 만든다면, 응답(responses)에 아래의 헤더를 포함 시키는 것을 고려 해 보심도 좋을 것 같습니다 :
- Server: 헤더는 User-Agent: 헤더와 유사합니다. Server: 헤더는 "Program-name/x.xx"포멧으로 서버측 프로그램을 구분 해 주는 역할을 합니다. 예를 들어 아파치 베타 버젼이 서버측에서 응답을 주고 있다면 서버는 "Server: Apache/1.2b3-dev"를 돌려 줄 것입니다.
- Last-Modified: 헤더는 리소스의 최종 업데이트 시간에 대한 정보를 가지고 있습니다. 이것을 이용해서 캐싱된 데이터를 업데이트 하는데 사용 될 수 있습니다. 시간은 아래와 같은 포멧으로 표시 될 수 있습니다 :
Last-Modified: Fri, 31 Dec 1999 23:59:59 GMT
Message Body
HTTP 메시지는 데이터 몸체(body of data)를 가질 수 있습니다. 응답의 경우에는 클라이언트로의 요청에 따른 결과 데이터 일 수도 있고, 에러가 발생 했다면 단순 에러 메시지 일 수도 있습니다. 요청의 경우에는 사용자가 입력한 데이터 이건나, 업로드를 하기 위한 데이터등 클라이언트로 서버로 보내지는 데이터들이 되겠지요.
만일 HTTP메시지에 바디(body)가 추가 된다면, 헤더라인에는 바디에 대해서 설명하는 헤더들이 추가 됩니다. 특히 :
- Content-Type: 헤더는 text/html 나 image/gif 같은 데이터의 MIME-type 나타냅니다
- Content-Length: 바디의 길이가 몇 바이트인지 나타냅니다
Sample HTTP Exchange
간단한 예제를 살펴 봄으로써 지금까지 설명했던 내용들에 대해서 되짚어 보도록 하겠습니다. 서버와 클라이언트 간에 오가는 메시지들을 직접 보시고 싶으시다면 웹서버에 텔넷을 이용하여 접속한 후, 직접 아래의 내용을 실습해 보는 것도 좋은 방법입니다.
아래의 URL에 있는 자원에 대한 요청을 보내 보도록 하겠습니다 :
처음으로 할 일은 www.somehost.com 호스트에 80번 포트로 연결되는 소켓을 생성하는 것입니다(왜 80번 포트냐면, 아무런 표시도 되어 있지 않은 HTTP는 기본적으로 80번 포트를 사용하도록 되어 있습니다). 소켓이 연결이 성공 했다면 아래의 메시지를 보내도록 합니다 :
From: someuser@jmarshall.com
User-Agent: HTTPTool/1.0
[blank line here]
서버는 동일한 소켓으로 아래와 같은 형식의 메시지를 보내 줄 것입니다 :
Date: Fri, 31 Dec 1999 23:59:59 GMT
Content-Type: text/html
Content-Length: 1354
<html>
<body>
<h1>Happy New Millennium!</h1>
(more file contents) . . .
</body>
</html>
응답을 보낸 후, 서버는 해당 소켓을 닫습니다. 다음 요청을 위해서는 새로운 컨넥션을 만들어야만 합니다.
이상으로 HTTP 트랜젝션에 대한 설명을 마쳤습니다. 간단하게 요약설명만하고 마무리하고자 했는데, 아직 제 실력이 부족한지라 짧은 글로는 명확한 전달을 하지 못 하는군요.
여기까지 읽어 주셔서 감사합니다.
Ref :
HTTP Made Really Easy : http://www.jmarshall.com/easy/http/