본문 바로가기

Front-End/Browser

브라우저의 렌더링 과정, 네트워크 통신, HTTP 통신 (1)

자바스크립트가 가장 많이 사용되는 분야는 역시 웹 브라우저 환경에서 동작하는 웹페이지 / app 의 클라이언트 사이드다.

JS는 브라우저에서 HTML, CSS 와 함께 실행된다. 따라서 브라우저 환경을 고려할때 더 효율적인 클라이언트 사이드 JS 프로그래밍이 가능하다.

이를 위해 브라우저가 HTML, CSS, JS 로 작성된 text 문서를 어떻게 파싱 ( 해석 ) 하여 브라우저에 렌더링 하는지 살펴보자.

파싱

파싱 (syntax analysis 구문분석) 은 프로그래밍 언어의 문법에 맞게 작성된 텍스트 문서를 읽어 들여 실행하기 위해

텍스트 문서의 문자열을 token 으로 분해 ( exical analysis ), 토큰에 문법적 의미와 구조를 반영하여

트리 구조의 자료구조인 파스트리 ( parse tree / syntax tree ) 를 생성하는 일련의 과정을 말한다.

일반적으로 parsing 이 완료된 이후엔 파스트리를 기반으로 중간언어 ( intermediate code ) 인 bytecode 를 생성하고

실행한다.

 

'토큰' 이란 문법적인 의미를 가지며, 문법적으로 더는 나눌수 없는 코드의 기본 요소를 의미.

'bytecode' 는 하드웨어가 아닌 가상 머신에서 실행하도록 만든 binary 코드를 의미.

 

브라우저는 다음과 같은 과정을 거쳐 렌더링을 수행.

  1. 브라우저는 HTML, CSS, JS, image, font 파일등 렌더링에 필요한 리소스를 requset 하고 서버로부터 response 받는다.
  2. 브라우저의 렌더링 엔진은 서버로 부터 response 된 HTML 과 CSS 를 파싱하여 DOM 과 CSSOM 을 생성하고 이를 결합하여 렌더 트리를 생성한다.
  3. 브라우저의 JS 엔진은 서버로 부터 response 된 JS 를 파싱하여 AST ( Abstarct Syntax Tree ) 를 생성하고, 바이트 코드로 변환하여 실행. 이때 JS는 DOM API를 통해 DOM 이나 CSSOM 을 변경할수 있다. 변경된 DOM 과 CSSOM 은 다시 렌더트리로 결합된다.
  4. 렌더 트리를 기반으로 HTML 요소의 레이아웃 ( 위치와 크기) 를 계산하고 브라우저 화면에 HTML 요소를 페인팅.

요청과 응답

브라우저의 핵심 기능은 필요한 리소스 (HTML, CSS, JS, image, font 등의 정적 파일 or 서버가 동적으로 생성한 data) 를 서버에 request 하고 response 받아 브라우저에 시각적으로 렌더링 하는것이다.

즉, 렌더링에 필요한 리소스는 모두 서버에 존재하므로 필요한 리소스를 서버에 요청하고 서버가 응답한 리소스를 파싱하여 렌더링 하는것이다.

서버에 요청을 전송하기 위해 브라우저는 주소창을 제공한다. 브라우저의 주소창에 URL을 입력하고 엔터키를 누르면 URL의 호스트 이름이 DNS 를 통해 IP 주소로 변환되고, 이 IP 주소를 갖는 서버에게 요청을 전송한다.

URI ( Unifrom Resource Identifier )

https:// www.mydomain.com  :80 / docs/search ? category=javascript&lang=ko #intro

Scheme          Host            Port       Path                       Query               Fragment

( Protocol )  ( Domain )                                           ( Query String )

예를 들어 https://poiemaweb.com 을 입력하고 엔터키를 누르면 루트 요청 ( / , 스키마와 호스트 만으로 구성된 URI 에 의 한요청 ) 이 poiemaweb.com 서버로 전송된다. 루트 요청에는 명확히 리소스 요청내용이 없지만, 일반적으로 서버는 / 요청에 대해 암묵적으로 index.html 을 응답하도록 기본 설정 되어있다.

따라서 서버는 루트 요청에 대해 서버의 루트 폴더에 존재하는 정적 파일 index.html 을 클라이언트 ( 브라우저 ) 로 응답한다. 만약 index.html 이 아닌 다른 정적 파일을 서버에 요청하려면 뒤에 /assets/data/data.json 과 같이 요청할 정적 파일의 경로 ( 서버의 루트폴더 기준 ) 와 파일 이름을 URI 의 호스트 뒤에 path 에 기술하여 서버에 요청.

주소창을 통해 서버에 정적 파일만을 요청할수 있는것은 아니다. JS 를 통해 동적으로 서버에 정적/동적 데이터를 요청할수도 있다. -> ajax , REST API

요청과 응답은 개발자 도구의 Network 패널에서 확인. 주소창에 https://poiemaweb.com 을 입력하고 엔터키를 눌러 서버에 루트 요청을 전송해 보자. 서버에 요청한 내용과 서버가 응답한 내용을 개발자 도구의 Network 패널에서 확인할수 있다.

개발자 도구의 Network 패널을 활성화 하기 이전에 브라우저가 이미 응답을 받은 경우 응답된 리소스가 표시되지 않는다. 패널에 아무런 리소스가 표시되지 않았다면 페이지를 새로고침 해야함.

index.html 뿐만 아니라 CSS, JS, img, font 들도 응답된것을 확인할수 있다. 요청하지 않은 이 리소스들은 왜 응답되는가?

이는 브라우저의 렌더링 엔진이 HTML 을 파싱하는 도중에 외부 리소스를 로드하는 태그, CSS 파일을 로드하는 link 태그, 이미지 파일 로드하는 img 태그, js 를 로드하는 script 태그등을 만나면 파싱을 일시 중단하고 해당 리소스 파일을 서버로 요청하기 때문이다.

브라우저에서 수많은 이미지와 동영상 등을 네트워크를 통해 다운받아 소비한다.

이런 콘텐츠들은 컴퓨터에 저장된 파일을 가져오는게 아닌 외부와의 통신을 통해 가져옴.

어떤 기술을 사용해 서버와 통신을 할수 있을까?

네트워크 통신을 위해 프런트엔드 개발자로써 알아야 하는 HTTP 와 비동기 API 에 대해 알아보자.

HTTP란?

HTTP(HyperText Transfer Protocol) 은 HTML 과 같은 하이퍼 미디어 문서를 전송하기 위한 프로토콜.

웹에서 이뤄지는 데이터 통신의 기초. 주로 TCP 사용. 기본 포트는 80번. HTTP를 통해 송수신 하는 데이터는

http: 로 시작하는 URL 로 접근

프로토콜은 데이터가 전송되는 방식을 결정하는 규약. 송신자와 수신자 사이의 합의를 통해 '데이터의 포맷은 이렇다', '오류 제어는 이렇게 해야한다' 같이 서로 통신을 할때 이해할수 있는 규칙을 만든것.

클라이언트 측과 서버는 프로토콜을 통해 정해진 포맷에 맞춰 통신.

클라이언트에서 서버로 전송하는 메시지를 요청(request)

이에 대한 답으로 서버에서 클라이언트 측으로 메시지를 응답(response)

HTTP 통신은 상태(state) 라는 개념이 존재하지 않는다. 즉 클라이언트와 서버가 연결되어 있지 않아 그전에 처리된 request 와 response 가 통신에 영향을 주지않고 각각 독립적으로 처리.

이런 특징 덕분에 서버 디자인을 단순하게 할수 있고, 송수신되는 정보 처리를 위한 공간을 동적으로 할당 할수 있으며 이를 제거해 줄 필요가 없다는 장점이 있다.

하지만 요청마다 필요한 정보를 모두 담아 보내야 하는 단점이 존재.

현재는 보안이 강화된 HTTPS(HyperText Transfer Protocol over SSL) 을 주로 사용.

https 의 경우 기본 포트로 443 번 사용. https: 로 시작하는 URL.

HTTP 버전은 0.9, 1.0 을 거쳐 1997년 등장한 1.1로 몇십년간 꾸준하게 확장되어 안정성을 유지.

이후 웹 app 이 점점 복잡해져 감으로 2015년 HTTP/2 가 표준화.

그리고 현재 TCP 대신 UDP 를 사용하는 HTTP/3 도 활발하게 개발.

TCP (Transmission Control Protocol) 와 UDP (User Data Protocol) 모두 OSI 7계층에서 4번째 전송계층 에서 사용되는 프로토콜이다. 주로 웹 브라우저들이 웹 서버에 연결할때 사용. TCP 의 경우 연결 지향적이며 순서가 보장되지만 상대적으로 느리며, UDP 의 경우 비연결 지향적이며 순서가 보장되지 않지만 빠른 장점이 있다.

상태코드

HTTP 응답 상태 코드는 HTTP 요청이 성공적으로 완료 되었는지 알려주는 세자리 정수.

응답은 5개의 그룹으로 나뉘며 상태 코드를 통해 성공 여부 뿐만 아니라 리다이렉트, 클라이언트, 서버의 에러에 관련된 정보를 알수 있다.

이 응답을 통해 사용자에게 적절한 안내를 할수 있으며 사이트의 동작을 제어.

  • 1xx ( informational ) : 서버에서 요청을 수신 했으며, 현재 처리중 이거나 정보를 알려줄 필요가 없을경우
  • 2xx ( Successful ) : 요청이 성공적으로 완료 되었음.
  • 3xx ( Redirection ) : 요청을 마치기 위해 다른 위치로 리다이렉션 하는것과 같이 추가로 동작을 취해야 할때 사용.
  • 4xx ( Client Error ) : 요청에 잘못된 구문이 포함되어 있거나 수행할수 없는 경우 반환.
    • 400 ( Bad Request ) : 요청오류. 잘못된 syntax 로 인해 서버가 해당 response를 이해할수 없을때.
    • 401 ( Unauthorized ) : 권한 없음. request를 받기 위해서는 인증을 받아야 함.
    • 403 ( Forbidden ) : 접근이 금지될때 반환.
    • 404 ( Not Found ) : 서버가 요청받은 리소스가 없을 때 반환. 잘못된 URL 로 요청을 하거나 리소스 자체가                                없을 때
  • 5xx ( Server Error ) : 서버가 유효한 요청을 수행하지 못했을 때 반환.
    • 500 ( Internal Server Error ) : 서버가 처리 방법을 모를경우 발생.
    • 502 ( Bad Gateway ) : 게이트웨이나 프록시 작업시 잘못된 응답을 수신한 것을 의미.
    • 503 ( Service Unavailable ) : 서버가 요청을 처리할 준비가 되지 않은경우 반환. 서버에 과부하가 걸리거나                                           배포도중 서비스가 중단되는 상황등에 해당 상태코드 반환.

FE 개발자로서 4xx 에러는 좀더 주의해야함.

예를 들어 잘못된 URL 을 입력했을때 404 페이지를 통해 사용자에게 잘못된 URL 을 입력했다는 것을 인지 시켜줘야 함.

400 에러가 발생했을 경우 유효하지 않은 요청이기 때문에 BE 개발자와 상호합의된 데이터 포맷에 대해 다시 이야기 해야함.

이 외에 각 HTTP 코드들에 따른 클라이언트 측의 대응책을 미리 마련하는것이 좋다.

메서드

클라이언트는 Request 메서드를 통해 웹 서버에 전송할 HTTP 요청의 목적, 종류를 나타낼수 있다.

메서드는 총 9가지가 존재, 각 메서드는 데이터의 조회나 변경등 목적에 맞춰 사용.

각각의 메서드 종류를 살펴보기 전 HTTP 메서드들이 갖는 특징을 살펴보자.

safe 

서버의 상태를 변경하지 않는 메서드의 경우 "safe" 하다고 함.

"읽기 전용" ? -> "safe"

이러한 메서드를 호출하는 경우 서버에 변경 사항을 동반하지 않기 때문에 불필요한 부하 x

대표적으로 GET, HEAD, OPTIONS 메서드는 "safe" 하다고 볼수있다.

멱등성 ( Idempotent )

동일한 요청을 한번 보낼때와 여러번 연속으로 보낼때 같은 동작을 하고, 서버의 상태 또한 같은동작일떄

"멱등성( Idempotent )" 을 갖는다 고 한다. 모든 "safe" 한 메서드는 "멱등성" 또한 갖는다.

"멱등성"을 가진 메서드가 모두 "safe" 한 메서드는 아니다.

대표적으로 GET, HEAD, PUT, DELETE 메서드가 "멱등성" 을 가지며, 이중 PUT 과 DELETE 는 서버의 상태를 변경하기 때문에 "멱등성"을 갖지만 "safe" 하지 않은 메서드이다.

Cacheable

응답을 저장해 향후 재사용을 할수 있는것을 의미.

각각의 특징을 기준으로 많이 사용되는 6가지 HTTP 메서드에 대해 살펴보자.

  • GET : 특정 리소스를 가져올때 사용.
  • POST : 서버로 데이터를 전송할때 주로 사용. 
  • PUT : 요청 payload 를 사용해 새로운 리소스를 생성하거나, 타깃을 payload로 대체. PUT 메서드는 POST 메서드와 다르게 멱등성을 가짐.
  • PATCH : PUT 메서드는 payload로 리소스를 대체하지만 PATCH는 리소스의 특정 부분을 수정할 때 사용.
  • DELETE : 특정 리소스를 제거할때 사용.
  • OPTIONS : 주어진 URL 또는 서버에 대해 허용된 통신 옵션을 확인할때 사용. 서버에서 지원하는 메서드를 확인 하거나 사전 요청 ( preflighted requests ) 을 보내는 용도로 사용.
이름 Request Body 가능 Response Body 가능 safe 멱등성 Cacheable HTML forms
가능
GET X O O O O O
POST O O X X 특정조건 O
PUT O X X O X X
PATCH O O X X X X
DELETE - - X O X X
OPTIONS X O O O X X

payload : 헤더와 메타데이터가 제외된 전송의 근본적 목적이 되는 데이터

헤더

HTTP header 는 Server 와 Client 사이에서 body 외에 추가적인 정보를 교환하는 방식.HTTP 메세지 제일앞에 삽입되며 수십개의 종류를 갖는다.헤더는 대소문자를 구분하지 않고 이름:값 ( Key-Value ) 형태로 이뤄짐.헤더는 사용되는 문맥 (Context) 을 기준으로 Entity 헤더, General 헤더, Request 헤더, Response 헤더로 분류.