====== HTTP ====== HyperText Transfer Protocol ([[하이퍼텍스트]] 전송 프로토콜). [[월드와이드웹]]의 기반이 되는 그 [[프로토콜]]로, 인터넷 주소창에서 허구한 날 나오는 그 ''%%http://%%''의 원천이다([[URI스킴]] 참고). 어떤 리소스([[HTML]] 파일 등등)를 가리키는 [[URL]]을 줬을 때 그 URL에 대한 권한이 있는 호스트(authority)를 찾은 뒤(이 부분은 [[DNS]]) 그 호스트로부터 실제 리소스를 받아 오는 부분이 HTTP로 이루어진다. 최신 버전은 [[1999년]]에 나온 **HTTP/1.1**. HTTP는 [[TCP IP]] 위에 위치한 어플리케이션 레이어에 속하며, 기본적으로는 [[TCP포트]] 80을 사용한다.(([[인터넷할당번호관리기관]](IANA)은 [[UDP포트]] 80도 [[http://www.iana.org/assignments/port-numbers|할당]]해 놓고 있지만, 이건 TCP 포트를 할당하면 가능한한 같은 UDP 포트도 할당해야 한다는 원칙 때문이지 실제로 쓴다는 건 아니다...)) 꼭 80을 써야 할 필요는 없으며, 따라서 종종 여는데 [[루트]] 권한이 필요 없는 8000, 8008이나 8080 포트를 대신 사용하는 경우도 볼 수 있다(뒤의 두 개는 IANA에도 "HTTP Alternative"로 등록되어 있다). ===== 고수준 구조 ===== HTTP는 기본적으로 (TCP이니만큼) [[클라이언트]]가 [[서버]]에게 특정한 리소스에 대한 요청(request)을 보내면 그 리소스를 담은 응답(response)을 되돌려 보내는 프로토콜로, [[FTP]] 같은 류의 비슷한 프로토콜과는 달리 [[세션]]의 개념이 없다(stateless). 다른 말로 하면, 서버가 응답을 보냈을 때 클라이언트의 상태를 절대적으로 바꾸는 방법은 없으며, 단지 클라이언트가 상태가 **바뀐 척** 행동해 달라고 요청하는 것만 가능하다(대표적인 방법으로 [[HTTP쿠키]] 참고). 클라이언트가 이 요청을 무시하면(이를테면, 쿠키를 허용하지 않는 등의 방법으로) 서버는 클라이언트의 상태에 대해 어떤 예상도 할 수 없다. 이런 의미에서 HTTP는 클라이언트보다는 서버에게 더 큰 부담을 지우는 프로토콜로, 여기에는 몇 가지 중요한 장점이 있으니: * 보통 클라이언트보다는 서버가 더 컴퓨팅 파워가 더 높기 때문에 클라이언트가 열악해도 된다. (요즘은 그다지 아닌 것 같다만.) * HTTP에서 가정하는 "리소스"의 대부분은 변경되지 않는 것으로, 굳이 세션을 가정할 필요는 없다. 덤으로 서버측 개발자는 굳이 변경되지 않을 리소스에 대해서까지 세션에 민감하게 만들 이유를 못 느끼게 된다. * 결과적으로, 클라이언트는 특정한 종류의 접근을 제외하면 서버의 상태에 대해서 자유롭게 가정할 수 있다. 예를 들어 [[웹크롤러]]는 자동화된 접근이 서버 상태를 바꾸지 않을 것이라고 가정할 수 있다. 이런 제약은 메소드(method)의 형태로 확인할 수 있다. 물론 현재의 웹에서 이런 특성이 항상 장점인 것만은 아니다: * TCP/IP에서 연결을 처음 만드는 과정은 생각보다 많은 시간을 차지하며, 실제 데이터가 오가는 시간이 충분히 짧아지면 연결 시간이 상당한 부하로 작용한다. 특히 HTML처럼 한 번에 여러 리소스가 한꺼번에 넘어 가야 하는 경우 이는 매우 심각한 문제가 되는데, 때문에 HTTP/1.1에서는 ''Connection: Keep-Alive'' 헤더가 추가되어 연결을 재활용할 수 있도록 되었다. 최근의 브라우저는 또한 한 서버에 여러 개의 연결을 한꺼번에 만드는 파이프라이닝(pipelining)을 지원하기도 하며, 심지어 [[구글크롬]]은 이 용도로 HTTP와 TCP/IP 사이에 중개 역할을 해 주는 [[SPDY]] 프로토콜을 만들기까지 했다! * 서버가 아무튼 상태를 유지시키려면 클라이언트에게 매 번 (보통 쿠키의 형태로) 상태를 넘겨 줘야 하는데, 클라이언트는 마음대로 행동할 수 있기 때문에 클라이언트로부터 다시 들어 오는 상태를 신뢰할 수 없다는 문제가 있다. 또한 상태의 크기가 클 경우 이 또한 상당한 부하로 작용한다. 이 때문에 대부분의 현대적인 웹사이트는 세션에 대한 키만을 클라이언트에게 노출시키는 [[서버측세션]]을 사용하고 있는데, 이는 클라이언트가 다른 세션의 키를 쉽게 예측할 수 없다는 성질에 기반한 것이다. * HTTP는 전통적으로 클라이언트가 연결을 시작하는(client-initiated connection) 프로토콜인데, 이 때문에 반대로, 뉴스 티커 같이 클라이언트는 가만히 있고 서버가 계속 데이터를 쏴 주는 경우 별도의 메커니즘이 필요하게 된다. 현재 여기에 대한 좋은 해결책은 아직 없으며 보통 클라이언트가 일정 시간마다 서버에게 요청을 다시 하면서 변경점을 확인하는 방법이 흔히 쓰이지만, 앞으로 [[WebSocket]]이 충분히 안정화되면 완전한 해결책이 나올 것으로 기대된다. ===== 저수준 구조 ===== HTTP는 텍스트 기반 프로토콜로 그 모습은 첫 줄을 제외하면 흡사 [[MIME]]과 유사하게 헤더와 데이터로 이루어져 있다. (사실은 [[인터넷미디어타입|MIME 컨텐트 타입]]도 함께 쓴다.) 첫 줄은 클라이언트와 서버가 서로 다르며, 클라이언트의 경우 요청하는 URL, [[#HTTP 메소드|메소드]](''GET'', ''POST'' 따위) 및 HTTP 버전이, 서버의 경우 [[#상태 코드]](200, [[HTTP 404|404]] 따위) 및 HTTP 버전이 들어 간다. 그 뒤에 따르는 HTTP 헤더는 해당 요청 및 응답에 부가적으로 따라 붙는 정보들을 담고 있으며, 이를테면 클라이언트가 보는 서버의 도메인(''[[가상호스트|Host]]''), 뒤에 따를 데이터의 종류 및 길이(''Content-Type''와 ''Content-Length''), [[HTTP쿠키|쿠키]] 정보(''Cookie'' 및 ''Set-Cookie''), 클라이언트가 서버 측에게 원하는 데이터의 구체적인 종류(''Accept'', ''Accept-Language'' 등), 클라이언트가 마지막으로 접근한 뒤 서버 쪽에 바뀐 게 있는지 확인하는 데 쓰는 헤더(''If-Modified-Since'' 등), 서버 소프트웨어 정보와 서버 측 시각(''Server''와 ''Date''), 클라이언트 소프트웨어 정보(''User-Agent'')까지 온갖 것들이 다 들어 가 있다. 이 헤더 및 첫 줄의 내용에 따라서 뒤에 데이터가 올 수도 있고 안 올 수도 있는데, 이를테면 클라이언트가 ''GET'' 메소드로 요청을 보낼 경우나, 서버가 클라이언트의 마지막 접근 뒤로 아무 것도 바뀐 게 없음을 알릴 경우(상태 코드가 304인 경우) 등등의 경우에 데이터가 생략될 수 있다. ==== HTTP 메소드 ==== HTTP 메소드는 크게 "안전한"(safe) 메소드와 안전하지 않은 메소드로, 또는 "반복 가능한"(idempotent) 메소드와 그렇지 않은 메소드로 분류할 수 있다. 전자는 일반적으로 서버의 상태를 변경하지 않는 메소드를 일컫으며, 후자는 말 그대로 여러 번 같은 요청을 보내도 서버의 상태를 바꾸지 않는(아예 안 보내는 것과는 별개이다) 메소드를 일컫는다. 실질적으로 이러한 특성이 제대로 지켜지는가는 미지수이지만(...) 많은 클라이언트가 이 특성에 의존하고 있으므로 웬만하면 서버측이 이 특성에 따르는 것이 후일의 이상한 버그를 방지할 수 있을 것이다.(([[lifthrasiir]]는 게시판에 ''GET'' 메소드로 글 삭제가 가능하게 만들어서 검색 엔진 봇이 한 번 긁어 갈 때마다 **게시판의 모든 글이 삭제되는** 사태가 발생했다는 전설을 들은 바가 있다...)) ? OPTIONS (안전, 반복 가능) ! 해당 리소스에 적용 가능한 메소드 목록을 나열한다. URL 대신 ''*''을 사용했다면 서버가 지원하는 메소드 목록을 얻을 수 있다. ? HEAD (안전, 반복 가능) ! 해당 리소스를 요청은 하되 실제 데이터는 빼고 헤더만 받아 온다. [[디버깅]]을 한다거나, 리소스의 변경 날짜만 알고 싶은 경우 등에 유용하다. ? GET (안전, 반복 가능) ! 해당 리소스를 요청한다. 리소스는 해당 요청에 의해 크게 변경되어서는 안 된다(하지만 많은 사람들이 이 규칙을 무시하는 경향이 있다). GET 요청에는 데이터가 붙을 수 없으며, 만약 데이터를 넣고 싶다면 URL에만 추가할 수 있기 때문에 큰 데이터를 붙여 넣을 수는 없다(보통 서버 소프트웨어가 제한을 걸기 때문에). ? POST ! 해당 리소스에게 주어진 데이터를 처리할 것을 요청한다. 데이터가 없을 수도 있는데 이 경우 URL만 가지고 무슨 일을 할 지를 결정하게 된다(이를테면 글 삭제라거나). GET과 더불어 매우 자주 쓰이며, 본래 PUT이나 DELETE 등의 메소드가 해야 할 일이 웹 브라우저들의 지원 부족 때문에 POST로 처리되는 경우도 흔히 볼 수 있다. ? PUT (반복 가능) ! 주어진 데이터를 서버에 올릴 것을 요청한다. 해당 리소스가 이미 존재한다면 주어진 데이터로 그 리소스를 갱신한다. 현실에서는 POST에 묻혀서 거의 쓰이지 않는다. ? DELETE (반복 가능) ! 해당 리소스를 삭제할 것을 요청한다. 해당 리소스가 이미 삭제되었든지 아예 원래 없었든지 아무튼 존재하지 않는다면 아무 일도 일어나지 않는다. 현실에서는 POST에 묻혀서 거의 쓰이지 않으며, 심지어 PUT보다도 안 쓰인다. ? TRACE (안전, 반복 가능) ! 주어진 요청을 그대로 되돌려 보낸다. 중간에 [[HTTP프록시|프록시]] 서버가 끼어 있을 경우 중간에 무슨 변경이 일어나는지 확인하는 데 유용하다. 이 밖에도 다른 확장에 의해 HTTP 메소드가 추가되는 경우도 있는데, 예를 들어 [[HTTP프록시]]에서 연결을 변경하는 데 사용하는 ''CONNECT'', [[WebDAV]]에서 쓰이는 ''PROPFIND'' 등등이 있다. 등록된 HTTP 확장 메소드의 목록은 [[http://tools.ietf.org/html/draft-ietf-httpbis-method-registrations|별도의 문서]]에서 볼 수 있다. ==== 상태 코드 ==== 상태 코드는 세 자리 숫자로, 그 범위에 따라서 크게 다섯 개로 나뉜다: * 100-199: 주어진 응답은 완전한 응답이 아니며, 뒤에 완전한 응답이 따라 올 수 있음을 나타낸다. * 200-299: 주어진 요청을 처리하는 데 성공했음을 나타낸다. 상태 코드는 요청의 처리 결과를 나타낸다. * 300-399: 주어진 요청을 처리하려면 클라이언트가 추가적인 동작(보통 또 다른 요청)을 해야 함을 나타낸다. 클라이언트에 따라서는 자동으로 그 다음 요청을 수행하지 않을 수도 있으며, 다음 요청을 수행한다 하더라도 [[무한루프]]를 방지하기 위해 5단계 이상은 진행하면 안 된다. * 400-499: 주어진 요청을 처리하는 데 실패했으며, 그 원인이 클라이언트에게 있음을 나타낸다. 여기에는 없는 리소스를 요청했다거나, 요청 형식이 틀렸거나, 인증을 안 했다거나 등등 여러 가지 이유가 포함될 수 있다. * 500-599: 주어진 요청을 처리하는 데 실패했으며, 그 원인이 서버에게 있음을 나타낸다. 주로 볼 수 있는 상태 코드는 다음과 같다: ? 200 OK ! 요청했던 리소스가 응답의 데이터 부분에 들어 있다. ? 206 Partial Content ! 요청했던 리소스의 "일부분"이 응답의 데이터 부분에 들어 있다. 이는 요청에 ''Content-Range'' 헤더가 들어 있을 경우에 해당하며, [[분할다운로드]]를 할 때 흔히 볼 수 있다. ? 301 Moved Permanently ! 요청했던 리소스가 주어진 URL로 영구적으로 이동했으므로 다음부터는 그 URL을 써야 한다. ? 302 Found ! 요청했던 리소스가 주어진 URL로 임시로 이동했음을 나타낸다. 그러나 POST 메소드의 경우 대부분의 웹 브라우저들이 표준과는 다른 동작을 하기 때문에, 웬만하면 303이나 307을 대신 써야 한다. ? 303 See Other ! 요청했던 리소스가 주어진 URL로 임시로 이동했으며, 다음 요청에 대해서는 항상 GET 메소드를 써야 한다. ? 304 Not Modified ! 요청한 리소스는 마지막으로 클라이언트가 기억하고 있던 것에서 변경 사항이 없다. ? 307 Temporary Redirect ! 요청했던 리소스가 주어진 URL로 임시로 이동했으며, 다음 요청은 이번 요청과 같은 메소드를 써야 한다. ? 401 Unauthorized ! 요청을 수행하려면 인증이 필요하다. 응답에는 ''WWW-Authenticate'' 헤더가 포함되며, 후의 요청이 올바른 응답을 ''Authorization'' 헤더로 보내 주면 요청을 수행할 수 있다. 그러나 인터페이스를 마음대로 바꿀 수가 없기 때문에 대부분의 [[로그인]] 폼에서는 그냥 POST 메소드를 쓰는 경우가 많다(...). ? 403 Forbidden ! 요청을 거절한다. 보통 권한이 없어서 나는 오류인 경우가 많다. ? 404 Not Found ! 요청한 리소스는 존재하지 않는다. 아마도 가장 유명한(200이나 304보다도 더 유명한) 상태 코드일 것이다. 자세한 내용은 [[HTTP 404]] 참고. ? 500 Internal Server Error ! 서버 문제로 요청을 처리하지 못 했다. 말 그대로 어떤 서버 문제에 대해서도 쓸 수 있는 만능(...) 상태 코드로, 서버가 부하가 걸려서 사용할 수 없을 때 쓰는 코드 503이 있긴 하지만 보통 그런 상황에서는 **그냥 응답이 안 오는 게 보통**이다. ===== 표준 ===== HTTP는 크게 세 개의 주요 버전이 존재했다: * [[http://www.w3.org/Protocols/HTTP/AsImplemented.html|HTTP/0.9]] (1991년): 표준이랄 게 없다. * HTTP/1.0 (1996년; RFC 1945): MIME과 비슷한 형태의 헤더가 추가되고 현재의 HTTP의 모습을 갖춘다. (이 표준에서 ''Simple-Request''와 ''Simple-Response''를 찾아 보면 이전의 HTTP가 얼마나 썰렁했는지 알 수 있다.) * HTTP/1.1 (1999년; RFC 2616): [[가상호스트]](''Host'' 헤더), 연결 재사용(''Connection: Keep-Alive'') 및 컨텐츠 협상(''Accept'' 헤더 등등) 등등이 추가되었다. 현재 거의 모든 소프트웨어는 HTTP/1.0과 HTTP/1.1을 올바르게 처리할 수 있으며, 클라이언트 단에서는 HTTP/1.1이 보편화되었다. HTTP/2.0에 대한 논의는 한동안 존재했으나 대부분의 경우 HTTP/1.1에 대한 확장이나 HTTP의 탈을 쓴 전혀 다른 프로토콜(WebSocket, WAKA, SPDY 등)로 귀결되고 말았다. (그러나 앞으로 후자가 탄력을 얻으면 HTTP/2.0의 일부가 될 가능성도 배제할 수는 없다.) ===== 바깥 링크 ===== * [[http://tools.ietf.org/wg/httpbis/|IETF Httpbis Working Group Status]] {{tag>인터넷}}