- URI와 URL의 차이
- HTTP 요청의 구성 요소
- HTTP 응답의 구성 요소
- Accept 필드가 있는 이유
- HTTP에서 한글을 쿼리 문자열로 사용하는 방법
- 포트란 무엇인가?
웹 브라우저와 웹 서버의 통신
다른 컴퓨터와 통신을 하기 위해선 정보를 주고받기 위한 '약속'이 필요하다. 그리고 www 세계에선 웹 클라이언트와 웹 서버가 HTML을 주고 받기 위해서 HTTP(Hyper Text Transfer Protocol)을 이용한다.
HTTP 요청
요청 라인(Request - Line)는 첫 번째 줄로 HTTP 요청에서 가장 중요한 부분이다.
GET http://www.wikibook.co.kr/webtext/http/index.html HTTP/1.1
a) 메소드
요청의 종류를 나타낸다. 즉, 'URI에서 지정한 정보를 보내 주세요'라는 의미가 된다.
b) URI
무엇을 원하는가? 즉, 리소스를 식별하는 정보를 전달한다.
c) HTTP 버전
HTTP 버전을 나타낸다.
두 번째 줄 이후의 나머지 부분은 요청 헤더 필드(Request-Header-Fields)라고 하며, 요청의 부가 정보를 나타낸다.
메시지 헤더는 필드 이름과 필드 값으로 구분되서 표현된다.
<필드 이름> : <필드 값>
----------------------------------------------------------------
(예시)
Host: goddaehee.tistory.comConnection: keep-aliveUpgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8Referer: http://goddaehee.tistory.com/Accept-Encoding: gzip, deflateAccept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7Cookie: menuEnabled=1;
a) Host
요청을 보낸 곳의 호스트명과 포트 번호를 지정한다.
b) User-Agent
웹 클라이언트의 웹 브라우저 종류와 버전을 나타낸다.
웹 서버는 User-Agent 필드 값을 통해서 접속해 온 클라이언트의 종류에 낮춰 최적의 콘텐츠를 돌려주는 데 사용한다. 만약 컴퓨터와 스마트폰 양쪽에서 열람할 수 있는 사이트가 있는 경우, 웹 서버는 User-Agent 필드를 참조해 해당 기기에 적합한 HTTP를 돌려준다.
c) Accept
웹 클라이언트가 받을 수 있는 데이터의 종류를 표시한다.
데이터의 종류는 Content-Type 이라는 형식으로 표시되는데, 클라이언트에서 받을 수 있는 데이터의 종류를 나타낸다. 텍스트 파일은 text/plain, JPEG 이미지는 image/jpeg 식으로 표시한다.
Accept 필드가 필요한 이유는 전송 효율을 향상시키기 위해서다. www 세계에선 HTTP를 이용하면 어떤 기계든지 클라이언트가 될 수 있다. 하지만 어떤 기기는 텍스트만 처리할 수 있고, 어떤 기기는 이미지만 처리할 수 있다. 웹 서버는 텍스트만 처리할 수 있는 클라이언트에게 이미지 파일을 전송할 이유가 하등 없기 때문에 불필요한 정보 전송을 차단하는 역할을 수행한다.
d) Accept-Language
웹 클라이언트가 받을 수 있는 자연 언어의 종류를 나타낸다. 자연 언어란 사람이 사용하는 언어를 가리킨다.
예를 들어 콘텐츠의 영어판과 한국어판이 있는 경우, Accept-Language 헤더에 따라 웹 서버가 클라이언트가 사용하는 언어에 맞는 콘텐츠를 보낼 수 있다.
HTTP 응답
상태 라인(Status-Line)는 첫 번째 줄로 HTTP 응답에서 가장 중요한 부분이다.
HTTP/1.1 200 OK
a) 상태 코드 (Status-Code)
클라이언트의 요청이 성공했는지 실패했는지 알 수 있다.
| 상태 코드 | 의미 | 설명 |
| 1xx | Information (정보) | 요청 처리가 계속되고 있음을 나타냄 |
| 2xx | Success (성공) | 요청이 성공했음을 나타냄 |
| 3xx | Redirection (리다이렉션) | 요청을 종료하려면 작업이 더 필요함을 나타냄 |
| 4xx | Client Error (클라이언트 에러) | 클라이언트 측에 기인한 오류로 요청이 실패함을 나타냄 |
| 5xx | Server Error (서버 에러) | 서버 측에 기인한 오류로 요청이 실패함을 나타냄 |
| 상태 코드 | 의미 | 설명 |
| 200 | OK | 요청이 정상적으로 완료됨 |
| 302 | Found | 요청된 리소스가 일시적으로 다른 URI에 속해 있음을 나타냄 |
| 401 | Unauthorized | 사용자 인증에 실패함 |
| 403 | Fobidden | 접속 권한이 없기 때문에 서버가 요청 실행을 거부함 |
| 404 | Not Found | 요청 URI와 일치하는 리소스를 찾지 못했음. 브라우저에 입력한 URI가 잘못됐을 경우 나타남 |
| 500 | Internal Server Error | CGI 프로그램 등 서버 내부의 프로그램 실행 과정에서 에러가 발생함 |
상태 라인 뒤이어 나오는 응답 헤더 필드(Response-Header-Fields)는 공백 라인 전까지 유지된다.
상태 라인에 이어서 나오는 것이 메시지 헤더이다. 응답에 관한 부가적인 정보가 들어 있다.
마지막으로 등장하는 것이 메시지 바디(Message-Body)다.
URI 와 URL 그리고 URN
원래 인터넷상에 존재하는 리소스의 위치를 지정하기 위해 URL이 최초로 등장했다.
URL은 도메인 주소 서버의 특정 디렉터리에 존재하는 리소스를 가리킨다. 만약 특정 파일이 다른 호스트로 이동하면 기존 URL으론 접속할 수 없다. 그래서 인터넷상의 존재하는 리소스에 통일된 이름을 정하자는 아이디어로 나온 것이 URN이다. 해당 파일(문서)가 물리적으로 어떤 위치에 존재하든 같은 URN으로 표시할 수 있다.
URI는 위치를 나타내는 URL과 이름을 나타내는 URN을 통일적으로 나타낸 것이다. 현재는 URI와 URL을 동일하게 사용하는 추세이다.
HTTP에서는 한 번에 하나의 리소스만 취득한다
HTTP는 한 번의 요청에 한 리소스만 취득하지 못한다. 따라서 웹 브라우저는 HTML을 해석하는 과정에서 특정 파일 태그를 확인하고, 그 태그의 src 속성에 지정된 URL의 파일을 다시 요청한다.
따라서 웹 클라이언트는 HTML을 필두로 CSS, JS, 이미지 파일 등을 반복적으로 요청하게 된다.
정보는 어떻게 인터넷의 대해를 건너는가?
인터넷에 접속된 모든 컴퓨터는 IP 주소라는 숫자로 식별된다.
IPv4 주소 체계는 8비트가 4부분으로 이뤄져 총 32비트로 구성된다. 그 결과 2의 32승, 즉 256 x 256 x 256 x 256으로 약 43억가지 숫자를 나타낼 수 있다.
IP 주소에 의지해 정보를 보내는 TCP/IP
IP 주소를 알면 특정 호스트를 지정할 수 있어 해당 호스트로 정보를 보낼 수 있다. 그러한 역할은 TCP/IP라는 프로토콜이 맡는다.
TCP/IP는 브라우저 등으로부터 받은 HTTP 요청 등의 정보를 패킷(Packet)이라는 작은 단위로 분할해 송신한다. 그리고 정보를 받은 쪽에서 그것을 원래대로 조립한 다음 웹 서버 등의 애플리케이션으로 넘긴다. 이러한 처리는 오늘날의 운영체제에 TCP/IP 프로토콜 스택이라는 프로그램에서 담당한다.
왜 번거롭게 패킷이라는 작은 단위로 정보를 보내는 것일까?
인터넷은 다양한 네트워크의 협조로 이뤄져있다. 그래서 정보 처리가 빠른 네트워크가 있는 반면, 정보 처리가 수월하지 않은 네트워크가 있을 수 있다. 만약 정보를 한 번에 보내려고 하면 예기치 못한 상황으로 송신이 실패할 수 있다. 그러면 모든 정보를 다시 보내야 하는 번거로움이 생긴다.
반면 패킷처럼 정보를 작은 단위로 조금씩 보내면 설령 송신에 실패하더라도 특정 패킷만 다시 보내면 되므로 전체적인 효율이 올라간다.
IP 주소를 결정하는 건 누구?
IP 주소는 전 세계에 하나밖에 없어야 한다. 따라서 IP 주소도 도메인명과 마찬가지로 특정 단체가 관리하고 있어서 신청한 후 IP 주소를 할당 받을 수 있다. 우리나라는 KISA(한국 인터넷 진흥원)이 관리하고 있다.
개인 사용자가 IP 주소를 일일이 신청하지 않아도 되는 이유는 우리가 이용하는 인터넷 서비스 업체(ISP)가 이미 대량의 IP 주소를 확보해 놓고 있어서 우리가 인터넷에 접속할 때마다 확보한 IP 주소 중 하나를 일시적으로 할당받기 떄문이다. 그래서 일반적으로 우리가 이용하는 컴퓨터의 IP 주소는 동적으로 바뀔 수 있다.
글로벌 IP 주소와 사설 IP 주소
기관에서 할당 받은 IP 주소는 인터넷상에서 유일한 주소가 된다. 이를 글로벌 IP 주소라고 한다.
IP 주소는 인터넷의 이용 뿐 아니라 현재 모든 네트워크 기기가 서로 정보를 주고받는 데 필요하다. 설령 인터넷을 이용하지 않더라도 사무실이나 가정에서 네트워크를 구축하려면 각 기기에 IP 주소가 있어야 한다. 이처럼 인터넷 등 다른 네트워크에 접속돼 있지 않는 네트워크를 사설 네트워크(private network)라고 한다. 이런 사설 네트워크엔 글로벌 IP 주소가 필요없다. 그래서 사설 네트워크에선 어떤 일정 번위의 IP 주소를 가지고 이용한다. 이를 사설 IP 주소라고 한다.
사설 IP 주소는 클래스 A, 클래스 B, 클래스 C 등으로 구분된다. 이 범위의 주소는 특별히 신청하지 않아도 조직 내에서 자유롭게 이용할 수 있다.
글로벌 IP 주소를 전화번호로, 사설 IP 주소를 내선 번호로 이해하면 좋다.
호스트명을 IP 주소로 변환하는 DNS
우리가 입력하는 도메인명을 IP 주소로 변환하는 시스템이 DNS(Domain Name System)이다. DNS는 도메인명과 IP 주소의 대응표를 가진 컴퓨터(DNS 서버)를 인터넷상에 배치해 놓고 있으면서 DNS 서버에 문의하면 도메인명에 대응하는 IP 주소를 알려준다.
잠시만, 하나의 IP 주소는 4바이트이며 도메인명은 최대 255바이트이므로 하나의 주소는 259바이트를 그리고 IP 주소의 총 개수는 약 43억 개이기 때문에 259 x 43으로 1테라 바이트 이상의 용량이 필요하다. 한 대의 DNS 서버가 이런 큰 용량을 가지고 모든 질의에 응답하는 건 너무 비효율적이다. 또 해당 서버가 고장나면 전 세계가 인터넷을 사용할 수 없게 된다.
이 점을 해결하기 위해 같은 도메인명에 대응하는 DNS 서버를 다수 준비해 정보를 분산 관리한다.
도메인명을 잘 보면 .net , .co.kr , .com 등 계층이 나뉜다. 인터넷상에는 각 계층에 대응하는 DNS 서버가 준비돼 있으며, 이들 DNS 서버에 질의함으로써 하위 DNS 서버의 주소를 알 수 있게 된다. kr, com, net, org 같은 최상위 도메인을 거치고 하위 DNS 서버에 질의해 나감으로써 최종적으로 원하는 호스트명에 대응하는 IP 주소를 알 수 있다.
호스트 내의 수신처를 결정하는 포트 번호
인터넷 세계에는 HTTP 이외에도 다양한 프로토콜로 정보를 주고받는다.
이메일 송수신에 사용되는 SMTP, 파일을 전송하기 위한 FTP, 멀리 떨어진 곳에서 컴퓨터를 조작하기 위한 Telnet이나 SSH 등 많이 존재한다. 이러한 프로토콜은 TCP/IP상에서 동작하며, 정보를 수신할 컴퓨터를 지정하는 데 IP 주소를 사용한다.
인터넷을 통해 정보를 수신할 컴퓨터에 도착한 패킷이 수식 측의 TCP/IP를 통해 원래 정보로 재구축 될 때, 수신한 정보가 어떤 프로토콜의 것이고, 이 정보를 처리할 애플리케이션이 무엇인지 알아야 하지만 TCP/IP는 알지 못한다. 그래서 포트(Port)가 등장했다.
TCP/IP를 통해 정보를 수신하는 애플리케이션은 반드시 대기 포트를 결정하고 정보를 기다린다. 반드시 하나의 애플리케이션은 하나의 포트만 사용할 수 있다. 컴퓨터 안에서 애플리케이션이 정보의 수신을 기다리기 위한 항구의 부두를 떠올리면 적합할 것이다. 그리고 이러한 포트는 0~65,535까지의 숫자로 표시되며, 애플리케이션이 각 부두에서 정보를 기다리고 있는 것이다.
그리고 각 프로토콜에는 기본적으로 포트 번호가 내정되어 있다. 애플리케이션이 어느 포트에서 정보를 기다리는지 표준으로 정해 놓았다. HTTP 프로토콜의 경우에는 80번이다.
웹 서버에 요청을 전달하는 방법
사용자가 브라우저의 폼에 요청 정보를 입력하면 그것을 바탕으로 서버 측에서 어떤 처리를 수행한다. 그 결과가 HTML로 되돌아와 웹 브라우저에 표시되는 것이다.
GET 메소드를 이용한 매개변수 전달
HTML의 form 태그에 보면 method 속성의 값이 'get'일 경우, 입력 필드의 값이 name 속성의 이름으로 웹 서버에 전송된다.
GET 메소드는 요청 라인의 URI에 '?'와 함께 쿼리 문자열(Query String)이 들어온다. 폼에 입력된 문자열 등을 웹 서버에 전달되는 데 사용된다. 각 부분은 '매개변수명=값'의 형식으로 표현된다.
POST 메소드를 이용한 매개변수 전달
GET 메소드를 이용한 매개변수 전달에는 한계가 있다. URL 속에 매개변수가 포함되기 때문에 어떤 정보를 웹 서버에 전송했는지 누설될 가능성이 크다. 또한 URL의 길이가 255문자로 제한돼 있어 많은 정보를 취급할 수 없다는 문제도 있다.
그래서 등장한 것이 POST 메소드를 이용한 매개변수 전달이다.
POST 메소드는 GET 요청을 사용했을 때에 있었던 쿼리 문자열이 없다. 대신 메시지 바디(Message-Body)에 매개변수로 들어간다. 이를 통해 브라우저의 주소창에 표시되지 않고, 매개변수가 웹 서버의 로그에 기록될 가능성도 줄어든다. 또한 메시지 본문에는 길이 제한이 없어서 매개변수의 양이 많아도 길이에 한계가 없다.
GET 과 POST 의 비교
GET 메소드는 매개변수 속에 사용자가 입력한 문자열이 포함되기 때문에 내가 검색한 구글 페이지를 다른 사람에게 URI를 통해서 공유할 수 있다.
이처럼 GET 메소드는 URL에 매개변수가 포함되기 때문에 매개변수째로 기억하거나 다른 사람에게 전달할 때 편리하다. 반면 POST 메소드는 메시지 본문에 매개변수가 들어 있기 때문에 즐겨찾기를 이용해 매개변수를 보존할 수 없다.
로그인 처리처럼 아이디와 패스워드 같은 기밀 정보를 송신할 경우나 결제 처리처럼 부작용을 동반하는 처리, 쿼리 문자열에 다 담을 수 없는 대량의 정보를 송신해야 할 경우엔 POST 메소드를 사용해야 한다. 이러한 조건에 해당하지 않으며 부작용이 없는 처리는 GET 요청을 이용하는 편이 매개변수째 보존할 수 있다는 장점을 활용할 수 있다.
퍼센트 인코딩을 이용해 한글을 전달
URL에서 이용할 수 있는 문자는 제한이 있다. 그래서 쿼리 문자열에 한글을 직접 사용할 수 없다. 한글뿐 아니라 공백 등도 이용 가능한 문자가 아니다.
그래서 텍스트 필드에 입력된 문자열이 퍼센트 인코딩이라고 불리는 방법으로 변환된다. 퍼센트 인코딩은 문자열을 문자 코드로 나타낸 것으로, 16진수로 표시한 각 값의 앞머리에 %(퍼센트)가 붙는 방식이다. 이렇게 URL에서 이용할 수 있는 문자열이 되어 URL에 사용된다.