Amazon Web Services 한국 블로그

웹 브라우저에 URL을 입력하면 어떤 일이 생기나요?

여러분은 매일 웹 브라우저를 열고 소셜 미디어, 뉴스, 전자 상거래 사이트 등 즐겨 찾는 웹 사이트를 탐색합니다. 주소창에 URL을 입력하거나 페이지 링크를 클릭하면 해당 페이지로 이동합니다. 그런데, 그 뒷단에서 무슨 일이 일어나는지 생각해 본 적이 있나요?

이 글에서는 웹 브라우저에 URL을 입력하고 Enter 키를 누르면 어떻게 되는지 살펴보겠습니다. (SW 엔지니어 인터뷰에서 나오는 단골 질문이기도 합니다. 실제 인터뷰에서는 이를 살펴보는 과정에서 웹 브라우저, PC의 운영 체제, 인터넷 서비스 제공업체, 웹 사이트를 호스팅하는 서버, 해당 서버에서 실행되는 서비스에 대한 지식 등이 약간 필요합니다. 이를 통해서, 실제 문제가 발생할 수 있는 위치와 성능 문제를 찾을 수 있는 위치를 파악하고 사용자에게 안전한 경험을 제공하고 있는지 확인하는 것이 중요합니다.

다만, 여기서는 좀 더 가볍게  웹 사이트, 서버 및 IP 주소 간의 관계와 그 뒤에 웹 브라우저에서 수행하는 단계를 간략히 살펴보겠습니다.

  • 웹 사이트를 호스팅하는 웹 서버의 위치 조회
  • 웹 서버에 연결
  • 특정 페이지를 가져오기 위한 요청 전송
  • 웹 서버의 응답을 처리
  • 사용자가 웹 사이트와 상호 작용할 수 있도록 페이지를 렌더링하는 방법

기본 지식

웹 사이트는 HTML, CSS, Javascript 및 이미지와 같은 파일 모음으로, 브라우저에 사이트, 이미지 및 데이터를 표시하는 방법을 지정합니다. 언제 어디서나 누구나 액세스할 수 있어야 하므로, 집에 있는 컴퓨터로 이들 정보를 호스팅하는 것은 확장 가능하거나 신뢰할 수 없습니다. 그래서, 인터넷에 연결된 외부 컴퓨터(서버라고 함)가 이러한 파일을 저장합니다.

웹 브라우저에서 https://channy.creation.net/blog와 같은 URL을 가리키면 브라우저는 인터넷에서 사이트를 호스팅하는 서버를 파악해야 합니다. 이는  channy.creation.net 도메인을 검색하여 주소를 찾는 것입니다.

내 컴퓨터, 웹 서버, 휴대폰, 스마트 냉장고 등 인터넷의 각 디바이스에는 모두 IP 주소라는 고유한 주소가 있습니다. IP 주소에는 3.34.220.186 와 같은 4개의 번호가 매겨진 부분이 있습니다.

하지만, 이러한 숫자는 기억하기 어렵습니다. channy.creation.net3.34.220.186보다 기억하기가 훨씬 쉽습니다. 휴대폰에 연락처 앱이 없어도 연락처의 모든 전화 번호를 기억해야 한다고 상상해 보십시오. 연락처 앱을 사용하면 이름 별로 전화번호를 조회할 수 있습니다.

인터넷에서도 마찬가지입니다. 도메인 이름 시스템(DNS)은 휴대폰의 연락처 앱과 같습니다. DNS는 브라우저가 인터넷에서 서버를 찾는 데 도움이 됩니다. DNS 조회를 수행하여 도메인 이름 channy.creation.net를 기반으로 서버의 IP 주소를 찾을 수 있습니다. DNS에 대한 자세한 내용은 여기에서 확인할 수 있으며, 도메인을 관리해주는 Amazon Route53 이라는 서비스도 있습니다.

이제  URL을 입력할 때, 웹 브라우저가 웹 서버와 어떻게 통신하는지 살펴보겠습니다. 주소창에 URL을 입력하든 현재 페이지에서 링크를 클릭하든 프로세스는 동일합니다.

전체 과정

웹 브라우저와 웹 서버와의 통신을 잘 이해하기 위해, AWS가 제공하는 가상 호스팅 서비스인 Amazon Lightsail 인스턴스와 Lightsail DNS 영역을 사용하겠습니다. Amazon Lightsail은 웹서버, DB서버, 로드밸런서, 도메인 네임(DNS), 콘텐츠 배포(CDN)를 한 곳에서 관리하는 간단한 서비스이기 때문에 웹 통신 뒷단의 많은 개념들을 쉽게 배울 수 있는 서비스입니다.

1. 웹 브라우저에 URL을 입력하고 Enter 키 입력

여기에 오기 위해 입력한 이 URL의 일부를 분류해 보겠습니다.

https://channy.creation.net/blog

통신 규약 (Protocol)

https://는 통신 프로토콜입니다. HTTPS는 Hypertext Transfer Protocol Secure를 나타냅니다. 이 스키마는 브라우저에 전송 계층 보안(TLS)을 사용하여 서버에 연결하도록 지시합니다. TLS는 인터넷을 통한 통신을 보호하는 암호화 프로토콜입니다. HTTPS를 사용하면 암호나 신용 카드 정보와 같이 브라우저와 서버 간에 교환되는 데이터가 암호화됩니다. ftp://, mailto:// 또는 file://도 보셨을 수 있습니다. 이는 브라우저가 처리하는 방법을 알고 있는 다른 프로토콜입니다.

도메인 (Domain)

channy.creation.net은 웹 사이트의 도메인 이름입니다. 기억하기 쉬운 주소이며 특정 서버의 IP 주소를 가리킵니다. 아래에서 Lightsail DNS 영역을 보면 Lightsail 인스턴스의 고정 IP 주소를 나타내는 Lightsail 인스턴스인 WordPress-1를 가리키는 DNS A 레코드를 볼 수 있습니다.

경로 (Path)

URL에 리소스에 대한 추가 경로가 있는 경우가 있습니다. 예를 들어, 이 URL https://channy.creation.net/blog/hello-world의 경우 blog는 서버에서 요청된 리소스인 hello-world로 이어지는 경로입니다. 이를 컴퓨터에 있는 파일의 디렉터리 구조나 기타 디렉터리처럼 생각할 수 있습니다. 정적 HTML, CSS, Javascript, 이미지 파일, 동적으로 생성된 콘텐츠에 상관없이 리소스를 구성하는 방법입니다.

리소스 (Resource)

이 URL을 브라우저에 입력하면 hello-world는 보려는 웹 사이트의 리소스 이름입니다. 때로 .html과 같은 파일 확장자로 볼 수 있는데, 이는 HTML 콘텐츠가 있는 서버의 정적 파일임을 나타냅니다. 이 URL과 같은 확장자가 없으면 일반적으로 서버가 이 콘텐츠를 생성했음을 나타냅니다. 예를 들어 뉴스 사이트는 사용자 지정, 최신 및 지역 뉴스 콘텐츠를 표시하며, 이는 사용자 또는 요청의 출처를 알 때만 수행할 수 있습니다.

2. 웹 브라우저가 도메인명의 IP 주소 조회

브라우저에 URL을 입력하고 Enter 키를 누른 후 브라우저는 인터넷에서 연결할 서버를 파악해야 합니다. 이렇게 하려면 입력한 도메인을 사용하여 웹 사이트를 호스팅하는 서버의 IP 주소를 조회해야 합니다. DNS 조회를 사용하여 이 작업을 수행합니다.

DNS는 복잡하고 매우 빨라야 하기 때문에 DNS 데이터는 웹 브라우저 사이의 서로 다른 계층과 인터넷의 다양한 위치에 임시로 저장됩니다. 이를 캐시(Cache)라고 부르는데, 웹 브라우저는 고유한 캐시, 운영 체제 캐시, 라우터의 로컬 네트워크 캐시, 회사 네트워크 또는 인터넷 서비스 제공업체(ISP)의 DNS 서버 캐시를 확인합니다. 이 때, 여러분 컴퓨터에 직접 사용자가 설정한 호스트 파일 (윈도우즈 디렉토리 아래 혹은 리눅스의 경우, /etc/hosts)에 있는 정보가 있는지 먼저 읽어옵니다.

Amazon Lightsail의 DNS 레코드를 관리할 경우, 이러한 도메인 네임 서버를 설정하고, 이들 서버들에서 DNS 레코드를 조회하는 것을 볼 수 있습니다. 이때, 고정 IP 주소를 레코드에 추가할 수도 있고, 필요하다면 로드밸런서에 지정하여 동적으로 IP 주소를 할당할 수도 있습니다.

만약, 웹 브라우저가 캐시 계층에서 IP 주소를 찾을 수 없는 경우 회사 네트워크 또는 ISP의 DNS 서버가 재귀적 DNS 조회를 수행합니다.  재귀적 DNS 조회는 인터넷에 있는 여러 DNS 서버를 요청하며, 검색될 때까지 DNS 레코드에 대해 더 많은 DNS 서버에 요청합니다. 웹 브라우저가 IP 주소로 DNS 레코드를 가져오면 인터넷에서 서버를 찾아 연결을 설정해야 합니다.

특정 웹 브라우저는 사용자가 링크를 따라가기 전에 미리 도메인 네임을 확인하는 DNS  프리페치(Prefetch)라는 기능을 가지고 있기도 합니다. 웹 페이지 내에 도메인명을 미리 확인되면 사용자가 해당 도메인으로 이동할 때, DNS 확인 시간으로 인한 효과적인 지연이 발생하지 않습니다. DNS 프리페치가 도움이 될 수 있는 사례는 검색 결과 페이지와 같이 다양한 도메인명의 링크가 있는 페이지를 보고 있는 경우입니다.

DNS 작동 방식에 대한 자세한 내용은 DNS 작동 방식에서 확인할 수 있습니다.

3. 웹 브라우저가 서버와의 TCP 연결 시작

인터넷에 연결된 웹 브라우저 요청 패킷은 일반적으로 TCP/IP(Transmission Control Protocol/Internet Protocol)라고 하는 전송 제어 프로토콜을 사용하여 라우터 장비, 인터넷 서비스 제공회사 교환기를 통해 이동되어, 통신 회사간 경로인 라우팅 테이블을 따라서 연결할 IP 주소가 있는 웹 서버를 찾습니다.

하지만, 웹 서버에 직접 도달하는 방법은 위치에 따라 효율적이지 않을 수 있습니다. 요즘에는 많은 웹 사이트들이 직접 서버에 연결하기 보다는 콘텐츠 전송 네트워크(CDN)를 사용하여 정적 및 동적 콘텐츠를 웹 브라우저 가까이에 위치 시킵니다.

예를 들어, 여러분이 좋아하는 동영상이나 음악 파일 같은 것은 멀리 외국에 있는 웹 서버에서 제공하기 보다는 여러분이 사용하는 인터넷 서비스 제공자들의 데이터 센터에 있는 콘텐츠 배포 서버에 위치해 있을 확률이 큽니다. 그래야만, 버퍼링 없이 서비스를 즐길 수 있을 테니까요.

AWS에서는 Amazon CloudFront라는 CDN 서비스가 있지만, Amazon Lightsail에서도 CDN 배포가 가능합니다.  Lightsail 인스턴스인 WordPress-1를 CDN 배포의 원본으로 설정합니다. 그러면, xxxxx.cloudfron.net 이라는 도메인 주소가 설정되고, 사용자가 접속을 요청하면  DNS는 원본 서버가 아니라 콘텐츠 배포 연결 지점의 IP 주소를 반환합니다.

즉, CDN은 콘텐츠를 사용자에게 더 가까이 제공하여 사이트의 원본 연결 성능을 개선하는 캐싱 서버의 글로벌 분산 네트워크입니다. Lightsail CDN은 AWS 글로벌 네트워크의 일부인 CloudFront를 사용합니다. 클라이언트 브라우저의 요청은 대기 시간이 매우 짧고 가용성이 높은 사설 네트워크를 활용할 수 있습니다.

이제 요청이 내 컴퓨터에서channy.creation.net로 이동하는 홉을 추적하기 위해 traceroute를 사용할 수 있습니다. 아래 이미지에서 첫 번째 hop(첫 번째 행)은 내 라우터에 대한 것입니다. 1은 ISP의 네트워크에 있고  2는 AWS 글로벌 네트워크에 있습니다.

웹 브라우저 요청은 인터넷 라우팅 테이블에 따라 경로를 따라서 순서대로 이동합니다. 각 요청은 가장 성능이 좋은 위치를 통해 지능적으로 라우팅되어 브라우저에 콘텐츠를 전송합니다. 이 경우, 웹 서버는 원본 서버도 CDN도 아닌 로드밸런싱(Elastic Load Balancing, ELB) 기능을 이용하고 있음을 알 수 있습니다. 로드밸런서는 여러 웹 서버의 부하 분산을 해주는 기능을 합니다.

웹 브라우저가 인터넷에서 서버를 찾으면 웹 서버와 TCP 연결을 설정하고, HTTP를 통해 평문 통신을 시작합니다. 그러나, HTTPS를 사용하는 경우 주고 받는 데이터의 암호화를 위한 TLS (Transport Layer Security) 핸드셰이크라는 추가 과정을 수행합니다. 이는 암호화를 할 상호 대상을 확인하는 것으로 TLS 핸드쉐이크는 데이터 보안 통신에 있어 매우 중요한 주제이므로 더 자세한 것은 직접 학습하시길 권장합니다. (실제 인터뷰에서는 TLS에 대한 집중 질문이 나올 수 있습니다.)

HTTP 통신이 진행될때, 웹 브라우저와 웹 서버 간의 통신이 어떻게 일어나는지 알아보기 위해서는 웹 브라우저의 개발자 도구를 사용하면 됩니다. 크롬의 경우, 보기 > 개발자 > 개발자 도구 에서 볼 수 있습니다.

특정 리소스를 가져오는데 필요한 DNS 찾기 시간, 연결 시간 등을 볼 수 있습니다.  웹 브라우저가 서버와의 연결을 설정했으면 다음 단계는 리소스 또는 페이지를 가져 오기 위해 HTTP 요청을 전송하는 것입니다.

4. 웹 브라우저가 HTTP 요청을 서버로 전송

웹 브라우저가 서버에 연결되면, HTTP(s) 프로토콜에 대한 통신 규칙을 따릅니다. 웹 브라우저가 페이지의 콘텐츠를 요청하기 위해 서버에 HTTP 요청을 전송하는 것으로 시작합니다. HTTP 요청에는 요청 라인, 헤더(또는 요청에 대한 메타데이터) 및 본문이 포함됩니다. 요청 라인에는 클라이언트(이 경우 브라우저)가 수행하려는 작업을 서버가 결정하는 데 사용할 수 있는 정보가 포함되어 있습니다.

요청 라인에는 다음이 포함됩니다.

  • GET, POST, PUT, PATCH, DELETE 또는 몇 가지 다른 HTTP 동사 중 하나인 요청 메서드
  • 요청된 리소스를 가리키는 경로
  • 통신할 HTTP 버전

URL 요청에 대한 요청 라인은 다음과 같습니다.

GET /blog/1620 HTTP/1.1

요청 라인은 서버에 /blog/1620에서 리소스를 가져오고 HTTP/1.1과 통신하기를 원한다고 알립니다.

HTTP 동사는 요청의 의미 의도를 표현한다는 것을 기억하십시오. POST, PUT 또는 PATCH 메서드를 사용하여 요청 경로에서 새 데이터를 생성하거나 기존 데이터를 업데이트하기 위해 저장할 서버로 데이터를 전송할 수도 있습니다. DELETE 메서드는 지정된 경로에서 리소스를 삭제합니다. 그러나, 서버가 모든 동사를 지원할 필요는 없다는 점을 아는 것이 중요합니다. 웹

서버는 DELETE 메서드에 200 OK 상태로 응답할 수 있지만 리소스로는 아무 작업도 하지 않을 수 있습니다. 이에 대한 자세한 것은 REST API에 대해 공부하시는 게 좋습니다.

다음은 요청 헤더(Request Header)입니다. 헤더는 요청을 라우팅하는 데 도움이 되는 추가 정보를 클라이언트에서 전달하고, 어떤 유형의 클라이언트(사용자 에이전트)가 요청을 수행하는지 나타내며, A/B 테스트, 블루/그린 배포 및 카나리 배포를 지원하는 데 사용할 수 있습니다. 헤더는 다음과 같은 키-값 페어입니다.

Host: channy.creation.net
User-Agent: curl/7.64.1
Accept: */*

요청의 마지막 부분은 본문입니다. 본문은 (보통) GET 요청에 대해 비어 있습니다. POST, PUT 또는 PATCH와 같은 리소스를 조작하는 요청의 경우 본문에는 생성하거나 업데이트할 클라이언트의 데이터가 포함됩니다. 요청 본문은 서로 다른 형식일 수 있으며 서버는 요청 헤더인 Content-Type을 기반으로 형식을 이해합니다.

다음은 요청 라인과 헤더가 있는 URL에 대한 전체 요청의 예입니다(GET이므로 본문이 없음).

GET /blog/1620 HTTP/1.1
Host: channy.creation.net
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="90", "Google Chrome";v="90"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0(Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36(KHTML, like Gecko) Chrome/90.0.4430.212 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
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: <https://channy.creation.net/>
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
dnt: 1
sec-gpc: 1

웹 서버가 클라이언트로부터 요청을 받으면 서버는 요청을 처리하고 응답을 다시 전송합니다.

5. 웹 서버가 요청을 처리하고 응답을 다시 전송

웹 서버는 요청을 받고 요청 라인, 헤더 및 본문의 정보를 기반으로 요청 처리 방법을 결정합니다. GET /blog/1620 HTTP/1.1 요청에 대해 서버는 이 경로의 콘텐츠를 가져오고 응답을 생성하여 클라이언트로 다시 전송합니다. 응답에는 다음이 포함됩니다.

  • 클라이언트에게 요청 상태를 알려주는 상태 라인
  • 브라우저에 응답 처리 방법을 알려주는 응답 헤더
  • 해당 경로에서 요청된 리소스 (HTML, CSS, Javascript, 이미지 파일과 같은 콘텐츠 또는 데이터)

상태 라인에는 HTTP 버전과 요청 상태의 숫자 및 텍스트 표현이 모두 포함됩니다. 응답은 다음과 같습니다.

HTTP/1.1 200 OK
Date: Tue, 25 May 2021 19:40:59 GMT
Server: Apache
X-Frame-Options: SAMEORIGIN
X-Powered-By: Express
Cache-Control: max-age=0, no-cache
Content-Type: text/html; charset=utf-8
Vary: Accept-Encoding
X-Mod-Pagespeed: 1.13.35.2-0
Content-Encoding: br
Keep-Alive: timeout=1, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked

<!DOCTYPE html>
<html lang="ko">
<head>
    나머지 HTML 항목

웹 브라우저는 200의 상태 코드를 성공한 것으로 간주합니다. 응답은 200이므로 브라우저는 응답을 렌더링하는 것을 알고 있습니다.

전송 받은 리소스는 텍스트(예: index.html) 또는 텍스트가 아닌 데이터(예: logo.img)의 정적 파일일 수 있습니다. 웹 브라우저가 항상 정적 파일을 요청하는 것은 아닙니다. 대부분 웹 서버가 동적 리소스를 생성하여 코드 조각이나 템플릿에서 HTML을 구축하고 동적 데이터와 결합하여 응답으로 텍스트로 다시 전송하여, 웹 브라우저가 페이지를 렌더링할 수 있습니다.

지금까지 서버가 브라우저로 다시 전송하기 위해 응답을 구축하는 방법을 알아보았는데, 이제 웹 브라우저가 응답을 어떻게 처리하는지 살펴보겠습니다.

6. 웹 브라우저가 콘텐츠 렌더링

웹 브라우저가 서버로부터 응답을 받으면 응답 헤더를 검사하여 리소스를 렌더링하는 방법에 대한 정보를 확인합니다. 위의 Content-Type 헤더는 브라우저에 응답 본문에서 HTML 리소스를 수신했음을 알립니다. 다행히 브라우저는 HTML로 무엇을 해야 하는지 알고 있습니다!

첫 번째 GET 요청은 페이지의 구조인 HTML을 반환합니다. 그러나, 웹 브라우저의 개발 도구를 사용하여 페이지(또는 웹 페이지)의 HTML을 검사하면 다른 Javascript, CSS, 이미지 리소스를 참조하고 웹 페이지를 설계된 대로 렌더링하기 위해 추가 데이터를 요청하는 것을 볼 수 있습니다.

브라우저가 HTML을 파싱하고 렌더링할 때 Javascript, CSS, 이미지 및 데이터를 가져오라는 추가 요청을 하고 있습니다. 이 중 많은 부분을 병렬로 수행할 수 있지만 항상 그런 것은 아닙니다.

여기서 HTML은 CSS나 JS 파일 리소스를 참조하는 것을 볼 수 있습니다. 웹 브라우저는 페이지에 스타일을 지정하기 위해 이 CSS 리소스를 가져오도록 서버에 후속 요청을 합니다. CSS 리소스에 대한 요청에 대한  Content-Type 헤더는 브라우저에 CSS를 렌더링하도록 지시합니다.

만약, 웹 브라우저가 이미지 리소스를 요청하면 Content-Type 헤더가 브라우저에 텍스트가 아닌 데이터임을 알려주고 그에 따라 렌더링하도록 지시합니다. 웹 브라우저의 렌더링 과정은 큰 기술 주제입니다. 여러분이 프론트엔드 엔지니어라면 꼭 알아두어야 할 지식이니 검색해서 익히시길 바랍니다.

마무리

지금까지 웹 브라우저에서 URL을 입력했을 때, 일어나는 일들을 간단하게 살펴보았습니다.

  1. 웹 브라우저에 URL을 입력하고 Enter 키를 누릅니다.
  2. 웹 브라우저가 도메인의 IP 주소를 조회합니다. (먼저 캐시를 찾고, 그 다음 DNS를 검색합니다.)
  3. 웹 브라우저가 찾은 IP 주소를 기반으로 서버와의 TCP 연결을 시작합니다.
  4. 웹 브라우저가 HTTP 요청을 서버로 전송합니다. (필요한 경우, HTTPS 보안 통신이 진행됩니다.)
  5. 웹 서버가 요청을 처리하고 응답을 다시 웹 브라우저로 전송합니다.
  6. 웹 브라우저가 전송 받은 콘텐츠를 렌더링합니다.

웹 브라우저에 URL을 입력하면 어떻게 되는지 알면 문제가 발생한 위치와 웹 사이트의 성능 문제를 찾을 위치를 파악하고 사용자에게 안전한 경험을 제공하는 데 도움이 될 수 있습니다.

마지막으로 해당 과정을 직접 확인하고 싶으시다면, Amazon Lightsail을 사용하여 자체 서버를 만든 후, 도메인 네임이나 콘텐츠 배포 설정, 혹은 로드밸런서 설정 등을 직접 해보실 수 있습니다.

AWS 프리 티어로 Amazon Lightsail을 무료로 시작할 수 있습니다. 1년 동안 50GB의 무료 콘텐츠 전송 네트워크(CDN) 배포, 1년 동안 5GB의 무료 객체 스토리지 번들, 3개월 동안 컨테이너, 인스턴스 및 데이터베이스 번들 무료 이용 혜택을 받을 수 있습니다.

Lightsail 튜토리얼을 통해 지금 시작해 보세요.

– Jenna Pederson & Channy(윤석찬);

이 글은 AWS Front-End Web & Mobile 블로그의 What happens when you type a URL into your browser? 한국어 번역을 편집한 것입니다.