HTTP 프로토콜 구조 개요와 예제

HTTP는 HyperText Transfer Protocol의 약자이다. HTTP는 아마도 인터넷에서 가장 많이 사용되는 프로토콜일 것이다.

HTTP 관련 표준은 다음과 같다.

RFC 1945 "Hypertext Transfer Protocol HTTP/1.0", 1996
RFC 2616 "Hypertext Transfer Protocol HTTP/1.1", 1999


HTTP는 OSI 7 layer에서 가장 상위 단의 application layer에 속한다. HTTP는 TCP/IP 연결 위에 올라가 있으며, HTTPS의 경우에는 SSL 위에 올라가 있다. 

================
HTTP     |      HTTPS
================
                    SSL
              =========
          TCP 
================
           IP
================



◾ Protocol overview

 


HTTP는 위 그림과 같이 HTTP 클라이언트에서 HTTP 서버로 요청을 보내고, 요청을 받은 서버는 클라이언트에게 상황에 맞는 응답을 보내는 형태로 이루어져 있다.


예를 들어 웹 브라우저에서 서버로 웹 페이지를 요청할 때 아래와 같은 요청 메시지를 서버에 보내고,

GET / HTTP/1.1
Host: ryanclaire.blogspot.com
Connection: keep-alive
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7

서버에서는 이 메시지에 대한 응답으로 아래와 같은 메시지를 클라이언트로 전송한다.

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Expires: Fri, 16 Oct 2020 03:24:32 GMT
Date: Fri, 16 Oct 2020 03:24:32 GMT
Cache-Control: private, max-age=0
Last-Modified: Thu, 15 Oct 2020 14:47:59 GMT
ETag: W/"5ff21f5b961238a44cb1cd27f6e753ccd873730fc8c28050213852c3fa960c18"
Content-Encoding: gzip
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Server: GSE
Alt-Svc: h3-Q050=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-27=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-T050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
Transfer-Encoding: chunked

--중략--



◾ HTTP Request Message

일반적인 HTTP Request Message의 구조는 위 그림과 같다. 맨 앞에 어떤 Request인지 들어가며, 그 다음 Request에 대한 부가내용이 들어간다. 마지막으로 Request에 따라 Request Body가 들어가기도 한다. Body와 Header는 빈 라인을 두어 구분하도록 되어 있다.


Request Line은 아래와 같은 구조로 되어있다.

Request_Method Request_URI HTTP_version

Request URI는 요청하는 리소스를 의미하며, HTTP version은 HTTP/1.0과 HTTP/1.1이 있다.


◻️ Request Method

HTTP protocol의 Request는 다음과 같다.

http 1.0 과 http 1.1

GET - 클라이언트가 서버에서 웹 리소스를 받아올 때 사용한다.

HEAD - HEAD를 사용하면 GET을 통해 받아오는 Response의 Header를 받아올 수 있다.

POST - 웹 서버에 데이터를 보낼 때 사용한다.

http 1.1

PUT - 서버에 데이터 저장을 요청할 때 사용된다 

DELETE - 서버에 데이터 삭제를 요청할 때 사용된다.

TRACE - 수행 작업의 diagnostic trace를 요청할 때 사용된다.

OPTIONS - 지원하는 Request 목록을 받아올 때 사용한다. 

CONNECT - 프록시에게 다른 호스트에 연결하고 콘텐츠를 분석하거나 캐시 없이 응답하도록 지시하는 데 사용된다. 


◻️ Request Header

Request Header에는 다음과 같은 내용들이 들어간다.

Host: 도메인 이름 

Accept: 클라이언트가 다룰 수 있는 MINE 타입이 열거된다.

Accept-Language: 클라이언트가 다룰 수 있고 선호하는 언어 타입이 열거된다.

Accept-Charset: 클라이언트가 다룰 수 있고 선호하는 문자 집합이 열거된다. Ex) UTF8, BIG5, ISO-8859-2 등

Accept-Encoding: 클라이언트가 지원하는 Encoding 타입이 열거된다. Ex) gzip, deflate 등

Connection: Request 후 연결을 닫을 것인지 유지할 것인지를 나타낸다. Close / Keep-Alive

User-Agent: Request가 만들어진 브라우저 타입을 알려준다.

Content-Length: POST Request를 사용할 때, Request Body의 데이터 길이를 나타낸다.

Content-Type: POST Request를 사용할 때, Request Body 데이터의 형식을 MIME 타입으로 나타낸다.



◾ HTTP Response Message

서버에서는 클라이언트의 Request에 위 그림과 같은 형태의 Response Message로 답한다. Request에 대한 Status와 Response Header 그리고 Response Body의 순으로 Response Message가 구성되어 있다. Response Header와 Response Body사이에는 Blank Line(‘\r\n’)을 두어 Header와 Body를 구분해야 한다. 


Status Line은 아래와 같은 형태로 이루어져 있다.

HTTP_Version Status_code Reason_Phrase

HTTP_Version은 HTTP/1.0과 HTTP/1.1 두가지이며, Reason_Phrase는 Status Code에 대한 짧은 설명문이 들어있다.


◻️ Status Code

Status Code는 3자리 숫자 코드이며 Request에 대한 응답으로 서버에서 생성한다. 상위 단위의 숫자에 따라 다섯 그룹으로 나눌 수 있다.

1xx (Informational) - 서버의 상태 정보.

100 Continue = 서버에서 Request를 받았으며, 이의 응답을 보내기 위해 처리하는 중이다. 


2xx (Success) - Request를 수신하였고, 의미를 이해했으며, 이를 처리했다는 것을 의미한다. 

200 OK = Request를 이행했다. 


3xx (Redirection) - Request를 처리하기 위해 다른 액션이 필요로 함을 의미한다.

301 Move Permanently = 요청된 리소스의 위치가 영구적으로 변경되었음을 의미한다. 

302 Found & Redirect = 요청된 리소스의 위치가 임시로 변경되었음을 의미한다.


4xx (Client Error) - Request에 문법 오류가 있거나 의미를 이해하지 못함을 의미한다. 

400 Bad Request = 서버에서 Request를 이해하지 못함, 구문의 오류가 있을 가능성이 있음을 의미한다. 

403 Forbidden = 클라이언트의 신원에 상관없이 서버에서 리소스 제공을 거부함을 의미한다. 

404 Not Found = 요청된 리소스를 서버에서 찾지 못함을 의미한다. 

405 Method Not Allowed = 클라이언트에서 요청한 Request를 서버에서 허용하지 않음을 의미한다. 


5xx (Server Error) - 서버에서 Request를 처리하지 못했음을 의미한다. 

500 Internal Server Error = 서버 내부 프로그램의 오류.

501 Method Not Implemented = Request method가 잘못되었음을 의미한다.

502 Bad Gateway = 프록시 또는 게이트웨이는 업스트림 서버에서 잘못된 응답을 수신했음을 의미한다.

503 Service Unavailable = 과부하나 유지 보수로 인해 서버가 응답할 수 없음을 의미한다. 


◻️ Response Header

Response Header에는 다음과 같은 내용들이 들어간다. 

Location: Request 완료 또는 새 리소스 식별을 위해 요청된 URI가 아닌 위치로 Redirection하는데 사용된다.

Server: Request 처리를 위한 서버의 소프트웨어 정보가 들어간다.

WWW-Authenticate: Request-URI에 적용될 수 있는 인증체계와 매개변수 정보가 들어간다.

Allow: Request-URI에서 지원하는 Method가 열거된다.

Content-Encoding: Body에 포함된 컨텐츠의 인코딩 형태를 알려주는데 사용된다. ex) Content-Encoding: gzip

Content-Type: 컨텐츠의 미디어 타입을 알려주는데 사용된다. Ex) Content-Type: text/html; charset=ISO-8859-4

Expires: 컨텐츠가 더 이상 유효하지 않을 수 있는 date/time을 제공하는데 사용한다. Ex) Expires: Fri, 16 Oct 2020 03:24:32 GMT

Last-Modified: 리소스가 마지막으로 업데이트되었다고 여겨지는 date/time을 제공하는데 사용된다.  Ex) Last-Modified: Thu, 15 Oct 2020 14:47:59 GMT

Accept-Ranges: 서버가 리소스 요청에 대한 수락 범위를 나타내는데 사용된다. Ex) Accept-Ranges: bytes 

ETag: 요청된 변형에 대한 엔티티 태그의 현재 값을 나타내는데 사용된다.

Content-Language: 컨텐츠에서 사용된 언어를 나타내는데 사용된다.

Content-Location: 메시지에 포함된 리소스의 위치를 공유하는데 사용된다.

Content-MD5: Body 컨텐츠의 MD5 코드를 제공하는데 사용된다.

Transfer-Encoding: 송수신자 간에 안전하게 전송하기 위해 메시지 본문에 적용된 변환 유형을 나타내다. Ex) Transfer-Encoding: chunked



◾ Request Example

HTTP의 Request와 Response의 메시지 내용(header + body)을 보기 위해 python으로 간단한 http client를 만들었다. Asyncio 모듈을 사용하였으며, https을 사용하기에 ssl을 사용하였다.

import asyncio

async def httpclient():
    try:
        reader, writer = await asyncio.open_connection(host='www.google.com',port=443,ssl=True)
    except OSError:
        print('connection fail')
        return
    
    writer.write(b'GET / HTTP/1.1\r\nHost:www.google.com\r\n\r\n')
    
    await asyncio.sleep(1)
    f = open('http GET response.txt','wb')
    
    while(1):
        data = await reader.read(1024)
        if len(data) > 0:
            f.write(data)
            print(data)
        else:
            break
    
    f.close()
    await asyncio.sleep(1)
    
    writer.close()
    await writer.wait_closed()
    print('connection was closed')
    

if __name__ == "__main__":
    
    try:
        loop = asyncio.get_running_loop()
    except RuntimeError:
        loop = None
    
    if loop and loop.is_running():
        tsk = loop.create_task(httpclient())
    else:
        asyncio.run(httpclient())



◻️ GET 예제

GET 메소드를 테스트하기 위해 host 주소를 www.ietf.org 로하고 Request 메시지를 아래와 같이 구성하였다.

“GET /rfc/rfc2616.txt HTTP/1.1\r\nHost:www.ietf.org\r\n\r\n”

Note) Request 헤더 뒤에는 반드시 blank line(\r\n)을 붙여야 한다. 


Response Message는 다음과 같다. 

HTTP/1.1 200 OK
Date: Sat, 17 Oct 2020 06:32:56 GMT
Content-Type: text/plain
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: __cfduid=daf28749b88389c67751c65d1471b6f891602916376; expires=Mon, 16-Nov-20 06:32:56 GMT; path=/; domain=.ietf.org; HttpOnly; SameSite=Lax; Secure
Last-Modified: Fri, 11 Jun 1999 18:46:53 GMT
ETag: W/"67187-34d0931a3e140-gzip"
Vary: Accept-Encoding
Strict-Transport-Security: max-age=31536000; preload
X-Frame-Options: ALLOW-FROM ietf.org *.ietf.org meetecho.com *.meetecho.com
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Content-Security-Policy: frame-ancestors 'self' *.meetecho.com *.ietf.org
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: *
Cache-Control: max-age=3600
CF-Cache-Status: HIT
Age: 255900
cf-request-id: 05d6dbf70b0000352c8489f000000001
Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Server: cloudflare
CF-RAY: 5e37fc381a6f352c-ICN

22ff






Network Working Group                                      R. Fielding
Request for Comments: 2616                                   UC Irvine
Obsoletes: 2068                                              J. Gettys
Category: Standards Track                                   Compaq/W3C
                                                              J. Mogul
                                                                Compaq
                                                            H. Frystyk
                                                               W3C/MIT
                                                           L. Masinter
                                                                 Xerox
                                                              P. Leach
                                                             Microsoft
                                                        T. Berners-Lee
                                                               W3C/MIT
                                                             June 1999


                Hypertext Transfer Protocol -- HTTP/1.1
---- 중략 ----


만약 Request 메시지에서 Host에 대한 내용 없이 Request Line만 전송하면

‘GET /rfc/rfc2616.txt HTTP/1.1\r\n\r\n’

다음과 같이 400 Bad Request 응답을 받게 된다.

HTTP/1.1 400 Bad Request
Server: cloudflare
Date: Sat, 17 Oct 2020 06:36:20 GMT
Content-Type: text/html
Content-Length: 155
Connection: close
CF-RAY: -

<html>
<head><title>400 Bad Request</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<hr><center>cloudflare</center>
</body>
</html>


◻️ HEAD 예제

HEAD 메소드는 GET 메소드의 Request 메시와 유사하게 구성할 수 있다.

“HEAD /rfc/rfc2616.txt HTTP/1.1\r\nHost:www.ietf.org\r\nConnection: Close\r\n\r\n”

HEAD 메소드의 응답은 아래와 같이 Response 메시지의 헤더만을 서버에서 보내온다.

HTTP/1.1 200 OK
Date: Sat, 17 Oct 2020 06:48:21 GMT
Content-Type: text/plain
Connection: close
Set-Cookie: __cfduid=ddb31de95b6981a9b0718cd3bdee388e21602917301; expires=Mon, 16-Nov-20 06:48:21 GMT; path=/; domain=.ietf.org; HttpOnly; SameSite=Lax; Secure
Last-Modified: Fri, 11 Jun 1999 18:46:53 GMT
ETag: W/"67187-34d0931a3e140-gzip"
Vary: Accept-Encoding
Strict-Transport-Security: max-age=31536000; preload
X-Frame-Options: ALLOW-FROM ietf.org *.ietf.org meetecho.com *.meetecho.com
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Content-Security-Policy: frame-ancestors 'self' *.meetecho.com *.ietf.org
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: *
Cache-Control: max-age=3600
CF-Cache-Status: HIT
Age: 256825
cf-request-id: 05d6ea1473000012ca05385000000001
Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Server: cloudflare
CF-RAY: 5e3812cd8e6612ca-ICN


◻️ POST 예제

POST 메소드는 아래와 같은 형식으로 구성할 수 있다.

POST request-URI HTTP-version
Host: host
Content-Type: mime-type
Content-Length: number-of-bytes
(other optional headers)

(query message)


Note) request body 마지막에 ‘\r\n’을 추가하면 안된다. 서버에 따라서는 오류로 인식한다.


예를 들어 아래와 같이 POST 메시지를 구성하여 ‘httpbin.org’에 요청하면,

'POST /post HTTP/1.1\r\nHost:httpbin.org\r\nContent-Type: text/plain\r\nContent-Length: 5\r\nConnection: Close\r\n\r\nHello'

아래와 같은 응답을 받을 수 있다.

HTTP/1.1 200 OK
Date: Sat, 17 Oct 2020 07:32:39 GMT
Content-Type: application/json
Content-Length: 332
Connection: close
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true


{
  "args": {}, 
  "data": "Hello", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Content-Length": "5", 
    "Content-Type": "text/plain", 
    "Host": "httpbin.org", 
    "X-Amzn-Trace-Id": "Root=1-5f8a9e17-1755758a691e5b0051977312"
  }, 
  "json": null, 
  "origin": "121.131.70.240", 
  "url": "https://httpbin.org/post"
}


만약 POST 메소드를 지원하지 않는다면 서버는 ‘405 Method Not Allowed’ 나 ‘501 Not Implemented’를 응답으로 보내온다.


댓글

이 블로그의 인기 게시물

간단한 cfar 알고리즘에 대해

쉽게 설명한 파티클 필터(particle filter) 동작 원리와 예제

python winsound를 이용한 윈도우 환경에서 소리 재생 예제

바로 프로젝트 적용 가능한 FIR Filter (low/high/band pass filter )를 c나 python으로 만들기