[ 살펴보기 ] HTTP - Basics

[ 살펴보기 ] HTTP - Basics

·

9 min read

HTTP ( Hypertext Transfer Protocol )는 html, css, javascript, 이미지 파일 등의 데이터를 요청하는 요청자( client )와 요청에 대한 데이터를 전달하는 응답자( server )사이의 communication을 위한 protocol이다. TCP/IP model에서 HTTP protocol은 application layer에 속한다. HTTP protocol의 version은 HTTP/0.9부터 시작해 현재는 HTTP/3까지 나와있지만 현재 가장 널리 사용되는 version은 HTTP/1.1이므로 해당 포스트는 HTTP/1.1을 기준으로 HTTP protocol을 살펴본다.

How HTTP works

HTTP protocol을 통해 resource를 요청하는 측을 client 그리고 요청한 resource를 제공하는 측을 server라고 한다. 우리가 흔히 사용하는 browser가 대표적인 http client이며 browser가 특정 사이트에 접속할 때 해당 사이트에 필요한 resource를 server가 제공한다. 여기서 server란 보통 nginx와 같은 software를 통해 web server 역할을 할 수 있는 computer를 말한다.

흔히 우리가 browser를 통해 특정 사이트에 접속하면 사이트 이용에 필요한 html, css, javascript 등 각종 파일을 http protocol을 통해 server 컴퓨터에 요청하게 되고 request를 전달 받은 server 컴퓨터는 http protocol을 통해 client가 요청하는 파일을 응답으로 전달하게 된다.

이렇듯 http client는 http protocol을 통해 http server ( 또는 web server, server )에 원하는 resource에 대한 request를 전달하고 http server는 request에 맞는 response를 전달한다. Browser는 일반적으로 사용하는 대표적인 http client이며 단순히 http server와의 communication을 위해서라면 postman이라는 software를 사용하거나 cURL이라는 command line 기반의 http client program을 통해서도 http server와 communication할 수 있다.

HTTP protocol의 중요한 특징 중 하나는 HTTP protocol은 stateless protocol이라는 점이다. 예를 들어 동일한 client가 request를 두 번 server로 전달한다고 하더라도 server 입장에선 그 두 개의 request는 서로 관련 없는 독립적인 request다. 그렇기에 server에서 request를 통해 client를 구분하기 위해서는 cookie이나 token의 적용과 같이 session 정보 유지를 위한 추가적인 조치가 필요하다.

HTTP Messages

Client와 server가 http protocol을 통해 서로 통신할 때 HTTP messages를 주고 받으며 통신한다. 그리고 client에서 server로 전달한 HTTP messsage를 request라고 하고 server에서 client로 전달한 HTTP message를 response라고 한다. HTTP/2 이전 version의 HTTP message는 text 기반으로 구성되어 있기에 내용을 보고 이해하는데 어렵지 않다. HTTP/1.1을 기준으로 HTTP messages의 기본 구조를 살펴보자.

Curl을 통해 localhost:3000에서 실행되고 있는 application server에 새로운 user 생성을 위해 post request를 전달한다고 가정해 보자. 그리고 user 생성을 위한 request body는 json format으로 전달하고 request endpoint를 localhost:3000/users라고 가정하면 client에서 전달하는 HTTP message ( request )의 기본 구조는 대략 다음과 같다.

POST /users HTTP/1.1
Host: localhost:3000
User-Agent: curl/8.9.1
Accept: */*
Content-Type: application/json
Content-Length: 20

{
  "userName":"test name"
}

Request message의 제일 첫 번째 line은 request-line이라고 부르며 method, request target, protocol 정보로 구성된다. 그리고 request-line 다음 line부터 http request header 정보로 구성된다. Content-type이나 User-agent등 request에 대한 metadata를 포함하고 있으며 request를 보내는 http client에 따라 default로 설정되는 header도 있고 직접 추가하여 request를 보낼 수 도 있다.

그리고 header section이 종료되는 부분의 empty line을 통해 header section이 끝났음을 구분하며 request의 body가 있으면 empty line 뒤에 request body가 추가된다. POST, PATCH, PUT method를 사용하는 request에서 body를 추가할 수 있으며 보통 resource를 새로 생성하거나 기존 resource를 수정할 때 필요한 data를 request body에 추가해 보낸다.

그리고 테스트에서 사용된 server가 위의 request에 대해 전달하는 HTTP message ( response )는 대략 다음과 같다.

HTTP/1.1 200 OK
content-type: application/json
Date: Thu, 09 Jan 2025 14:39:39 GMT
Connection: keep-alive
Keep-Alive: timeout=5

{"success":true,"method":"post"}

Server에서 client로 전달하는 HTTP message ( response ) 역시 client에서 server로 전달하는 HTTP message ( request )와 다르지 않다. 우선 start-line으로 시작하며 protocol, status code, status text로 구성된다. 그 다음 line부터 http header section이 시작되고 header section이 종료되는 부분의 empty line을 통해 header section이 끝났음을 구분하며 response의 body가 있으면 empty line 뒤에 response body가 추가된다

URL ( Uniform Resource Locators )

URL은 server에 존재하는 resource에 접근하기 위해 사용하는 address를 뜻한다. resource에 접근하기 위해 사용하는 protocol, resource의 위치 등의 정보가 모여 하나의 resource를 구분하는 url이 형성된다. 추가로 URI( Uniform Resource Identifiers )의 종류 중 하나가 URL이며 URL은 URI에 속해 있는 개념이다.

예를 들어 다음과 같은 url이 있다고 가정해보자.

https://example.com:3000/order?page=1&limit=10#mybutton

위의 url은 아래의 component들로 구성되어 있다.

  • protocol : resource를 요청하기 위해 사용하는 protocol이다. 위의 예제에선 https로 명시되어 있다.

  • host : resource가 위치해 있는 host ( server )의 domain name 또는 ip address다. 위의 예제에서 example.com으로 명시되어 있다.

  • port : resource를 제공하는 server application이 listen하는 port를 설정한다. 위의 예제에서는 3000으로 명시되어 있다. url에서 port 번호를 생략하면 protocol에 따라 default port가 적용된다. ( http : 80, https : 443 )

  • path : 요청하는 resource의 상세 location 정보다. /order.html과 같이 실제 file name이 될 수도 있고 /order와 같이 file name이 아닌 요청할 resource의 name 형식으로 명시할 수도 있다. 어떤 형태의 url path를 통해 resource를 요청할 수 있는지는 web server의 구성에 따라 달라진다. 위의 예제에서 /order로 명시되어 있다.

  • query parameter : 필수 값은 아니며 resource를 요청할 때 filter등의 목적으로 query parameter를 함께 명시하여 보낼 수 있다. 위의 예제에서 ?page=1&limit=10으로 명시되어 있으며 page와 limit 두 개의 query parameter가 명시되어 있다.

  • fragment : 필수 값은 아니며 return된 resource에서 특정 section을 가리킨다. 위의 예제에서 #mybutton으로 명시되어 있다. server 측에서 fragment에 따라 resource를 가려주진 않고 client side에서 return 받은 resource의 특정 section을 가리킬 때 사용한다 ( html page에서 특정 id를 가진 element와 같은 )

MIME ( Multipurpose Internet Mail Extensions )

HTTP server가 http request에 따라 resource를 제공할 때 해당 resource가 어떤 유형의 파일인지 client에 알려주기 위해 Content-Type header에 MIME type 정보를 함께 전달한다.

예를 들어 전달하는 file이 html이라면 MIME type은 text/html가 될 것이고 png format의 image라면 image/png가 될 것이다. Browser는 Content-Type에 설정된 MIME type을 기반으로 response로 전달 받은 resoource를 어떻게 처리할지 결정하므로 http server에서 올바른 MIME type을 함께 전달하는 것이 중요하다.

Method

Client가 server로 request를 전달할 때 request에는 http method가 포함된다. 그리고 server는 request에 포함된 method에 따라 해당 요청이 특정 resource나 data를 요구하는 요청인지 혹은 새로운 resource나 data를 생성하는 요청인지 혹은 resource나 데이터를 삭제 하기 위한 요청인지 구분하여 그에 맞게 처리한다.

HTTP protocol의 대표적인 method는 다음과 같다.

  • GET : server의 특정 resource나 data를 요청

  • POST : 새로운 resource나 data 생성을 요청

  • PUT : 기존의 resource나 data에 대한 업데이트 요청 ( 기존 data를 새로운 data로 완전히 교체하는 방식으로 )

  • PATCH : 기존 resource나 data에 대한 업데이트 요청 ( 기존 data의 일부를 수정하는 방식으로 )

  • DELETE : 기존 resource나 data를 삭제하는 요청

  • HEAD : server의 특정 resource나 data를 요청하되 response에 HTTP header만 포함시킬 것을 요청 ( 즉, 실제 resource나 data가 response body에 포함되지 않는다 )

Status code

Client의 request에 대해 server가 response를 전달할 때 response는 그에 맞는 status code를 포함한다. status code는 request 처리의 성공 여부와 같이 request 처리 결과 상태를 나타내기 위해 사용한다. Response에 설정할 수 있는 status code는 다양하지만 크게 다음 다섯 범위로 나뉜다.

  • 100 번대 status code : Information status code로서 request가 전달 되었고 처리 중임을 나타내는 status code로 100번대 status code를 사용한다.

  • 200 번대 status code : success status code로서 request가 정상적으로 처리되었음을 나타내는 status code로 200번대 status code를 사용한다.

  • 300 번대 status code : redirection status code로서 처음 보냈던 request의 resource location이 변경되었으며 redirection이 필요함을 나타내는 status code로 300번대 status code를 사용한다.

  • 400 번대 status code : client error status code로서 client에 보낸 request에 이상이 있음을 나타낸는 status code로 400번대 status code를 사용한다.

  • 500 번대 status code : server error status code로서 reqeust를 처리하는 server에 이상이 있음을 나타내는 status code로 500번대 status code를 사용한다.

각 category 마다 사용할 수 있는 status code는 상당히 많으므로 그 중 일부를 살펴보자. 사용할 수 있는 status code list와 자세한 사항은 MDN documentation을 통해 확인할 수 있다. ( Reference - HTTP response status codes )

  • 101 ( switching protocol ) : client request의 Upgrade header에 의해 server가 사용하는 protocol을 전환함을 나타낸다.

  • 200 ( ok ) : request가 정상적으로 처리되었음을 나타낸다.

  • 201 ( created ) : request가 정상적으로 처리되었고 새로운 resource가 생성되었음을 나타낸다.

  • 204 ( no content ) : request가 정상적으로 처리되었으며 client에 다시 전달할 content가 별도로 존재하지 않음을 나타낸다.

  • 301 ( moved permanently ) : request resource의 url이 영구적으로 변경되었음을 나타낸다.

  • 302 ( found ) : reqeust resource의 url이 임시적으로 변경되었음을 나타낸다.

  • 400 ( bad request ) : client request에 문제가 있어 server에서 request를 처리하지 못했음을 나타낸다.

  • 401 ( unauthorized ) : resource를 요청하기 위해 client가 authenticated 되어야 함을 나타낸다. MDN에 따르면 HTTP standards에서는 “unauthorized”라고 명시하고 있지만 의미상 “unauthenticated”로 해석하는 것이 보다 적절하다고 말하고 있다 ( Reference - Client error responses )

  • 403 ( forbidden ) : authenticated된 user이지만 resouece를 요청하기 위해 필요한 권한을 가지고 있지 않음을 나타낸다.

  • 404 ( not found ) : request resource를 찾을 수 없음을 나타낸다. client가 존재하지 않는 resource를 요청하거나 보안을 위해 authenticated 되지 않은 user가 resource를 요청한 경우 resource의 존재 여부를 숨기기 위해 403 대신 404 status code를 return해줄 수 도 있다.

  • 405 ( method not allowed ) : client가 특정 resource를 제공하는 server endpoint ( url )에서 지원하지 않는 http method를 통해 request를 보냈음을 나타낸다.

  • 500 ( internal server error ) : server에 문제가 있어 request를 처리하지 못했음을 나타낸다.

  • 503 ( service unavailable ) : server가 점검 등의 이유로 일정 시간 request를 처리하지 못하는 상태임을 나타낸다. Server에서 해당 status code를 return할 때 보통Retry-After header를 통해 recovery 시간 정보를 함께 담아서 전달한다.

HTTPS

HTTP protocol을 통해 client-server는 서로 data를 보내며 통신할 수 있지만 data가 암호화되지 않고 전달되기 때문에 누군가 도중에 data를 탈취 하면 비밀번호와 같은 정보가 그대로 노출되므로 보안에 있어 취약하다. 그렇기에 http protocol을 통해 전달되는 data를 암호화 하여 data가 탈취 되더라도 탈취자가 data가 무엇을 의미하는 data인지 알 수 없도록 암호화 해서 전달해야 하는데 이를 위해 TLS ( Transport Layer Security )를 통해 data 암호화와 같은 보안 요소를 추가할 수 있다.

TLS는 TCP/IP model에서 transport layer에 위치하며 application layer에서 data를 전달할 때 TLS를 통해 data를 암호화할 때 사용하는 protocol이 https ( HyperText Transfer Protocol Secure )다. 즉, https는 http와 완전히 다른 protocol은 아니며 http를 통해 data를 전달할 때 TLS를 통해 암호화된 data를 전달할 때 사용하는 protocol이다.

HTTPS를 통해 client와 server가 communication하는 과정은 대략적으로 다음과 같다.

  • client가 server로 request를 요청하여 server와 connection을 시작한다.

  • 그리고 client와 server는 handshake라는 과정을 통해 secure connection을 수립한다. handshake의 과정은 다음과 같다.

    • Client Hello : client가 지원하는 TLS version, encryption algorithms과 encryption을 위한 session key로 사용될 random number ( client random ) 값을 server로 전달한다.

    • Server Hello : server는 사용할 TLS version과 encryption algorithm 그리고 random number ( server random ) 값과 public key가 포함된 TLS certificate을 client에 전달한다.

    • Certificate Verification : client는 server가 전달한 certificate이 유효한 certificate인지, certificate에 등록된 domain이 client가 request를 보내는 server와 일치하는지 그리고 신뢰할 수 있는 Certificate Authority( CA )를 통해 발급된 certificate인지 검증한다.

    • Key Exchange : client가 certificate을 검증하고 나면 client와 server는 data encryption을 위해 사용할 session key ( 또는 secret key )를 생성하여 전달한다. key exchange를 위한 method로 RSA 또는 Diffie-Hellman이 주로 사용되며 method에 따라 session key 형성 방법 및 key exchange 방법에 차이가 있다.

    • Finished Message : client와 server는 finished message를 교환하고 handshake 과정이 종료된다.

  • handshake 과정이 종료되고 client-server 사이에서 전달되는 data는 handshake 과정에서 생성된 session key를 통해 암호화되어 전달된다.

HTTPS Key Exchange

HTTPS handshake key exchange 과정에서 사용되는 대표적인 method는 다음 두 가지가 있으며 사용되는 method에 따라 session key의 형성 방법과 key exchange 방법이 달라진다.

  • RSA : client는 session key를 생성하고 handshake 과정에서 server로 부터 전달된 public key ( TLS certificate에 포함된 )을 통해 session key를 암호화해서 server에 전달한다. 그리고 server는 private key를 통해 session key를 해독한다.

  • Diffie-Hellman : handshake의 client hello 과정에서 client는 server로 public key를 전달하고 server hello 과정에서 server 역시 client로 public key를 전달한다. client과 server는 private key와 서로에게 전달 받은 public key를 통해 session key를 계산한다. ( Diffe-Hellman method에서 session key는 client-server 사이에서 전달되지 않는다 )