Protokol

HTTP/2 dan HTTP/3 untuk Developer

Panduan lengkap evolusi protokol web dari HTTP/1.1 ke HTTP/2 dan HTTP/3 β€” multiplexing, server push, QUIC protocol, header compression HPACK/QPACK, dan strategi optimasi performa

1. Evolusi HTTP: Dari 1.0 ke 3.0

HTTP (HyperText Transfer Protocol) telah berevolusi secara dramatis sejak pertama kali diusulkan oleh Tim Berners-Lee pada tahun 1991. Pemahaman tentang evolusi ini membantu developer memahami mengapa HTTP/2 dan HTTP/3 dirancang seperti sekarang.

Timeline Evolusi HTTP

Versi Tahun Transport Inovasi Utama
HTTP/0.91991TCPHanya GET, satu baris request, tanpa header
HTTP/1.01996TCPHeader, status codes, metode POST/HEAD
HTTP/1.11997TCPPersistent connections, pipelining, chunked encoding
HTTP/22015TCP + TLSBinary framing, multiplexing, server push, HPACK
HTTP/32022 (RFC 9114)QUIC (UDP)0-RTT, connection migration, QPACK, independent streams

Masalah HTTP/1.1 yang Dipecahkan

Text
# Masalah 1: Head-of-Line Blocking di HTTP/1.1
# Setiap request/response harus tunggu giliran

Client                  Server
  |--- Request A ------->|
  |                       |
  |<-- Response A --------|  ← Harus selesai dulu
  |                       |
  |--- Request B ------->|  ← Baru bisa kirim B
  |                       |
  |<-- Response B --------|

# Masalah 2: Pipelining yang tidak reliable
# Browser men-disable pipelining karena masalah di proxy lama

Client                  Server
  |--- Request A ------->|
  |--- Request B ------->|  ← Dikirim tanpa tunggu
  |--- Request C ------->|
  |                       |
  |<-- Response A --------|  ← HARUS berurutan
  |<-- Response B --------|  ← Bisa ter-block jika A lambat
  |<-- Response C --------|

# Masalah 3: Connection overhead
# HTTP/1.1: browser buka 6-8 koneksi TCP paralel per domain
# β†’ Memory overhead, congestion window terpisah
# β†’ TLS handshake dilakukan untuk setiap koneksi

2. HTTP/2 Fundamentals

HTTP/2 (RFC 7540, 2015) merupakan lompatan besar dalam protokol web. Berbasis pada protokol SPDY yang dikembangkan Google, HTTP/2 memperkenalkan binary framing layer di atas TCP yang memungkinkan multiplexing, flow control, dan prioritas stream.

Perubahan Paradigma

Aspek HTTP/1.1 HTTP/2
FormatText-basedBinary framing
HeaderText, diulang tiap requestBinary, compressed (HPACK)
MultiplexingTidak (parallel TCP)Ya, dalam satu koneksi
PrioritasTidak adaStream dependency + weight
Server PushTidakYa
Flow ControlTidakPer-stream + connection level
Connection1 request per koneksi (atau pipelining)Ratusan stream dalam 1 koneksi

HTTP/2 Binary Frame Format

Text
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                 Length (24 bit)                                |
+---------------+---------------+-------------------------------+
|   Type (8)    |   Flags (8)   |
+-+-------------+---------------+-------------------------------+
|R|                 Stream Identifier (31)                      |
+=+=============================================================+
|                   Frame Payload (0...2^24-1)                   |
+===============================================================+

# Frame Types:
# 0x0 DATA         β€” Payload data
# 0x1 HEADERS      β€” Request/response headers
# 0x2 PRIORITY     β€” Stream priority
# 0x3 RST_STREAM   β€” Stream termination
# 0x4 SETTINGS     β€” Connection parameters
# 0x5 PUSH_PROMISE β€” Server push announcement
# 0x6 PING         β€” Connection liveness
# 0x7 GOAWAY       β€” Graceful shutdown
# 0x8 WINDOW_UPDATE β€” Flow control
# 0x9 CONTINUATION β€” Continued header block

Connection Upgrade (h2)

HTTP/2 biasanya dinegosiasikan selama TLS handshake menggunakan ALPN (Application-Layer Protocol Negotiation). Browser modern hanya mendukung HTTP/2 di atas TLS (h2), sedangkan versi plaintext (h2c) hanya untuk spesifikasi/konfigurasi khusus.

Text
# TLS ALPN Negotiation untuk HTTP/2

Client                                    Server
  |                                         |
  |--- ClientHello                          |
  |    ALPN: [h2, http/1.1]  ----------->   |
  |                                         |
  |<-- ServerHello                           |
  |    ALPN: h2  (memilih HTTP/2)           |
  |                                         |
  |==== HTTP/2 Connection Preface =========>|
  |    SETTINGS frame                       |

# Connection Preface:
# Client: "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" + SETTINGS frame
# Server: SETTINGS frame + possible ACK

# Alternatif upgrade dari HTTP/1.1 (tanpa TLS):
# GET / HTTP/1.1
# Host: example.com
# Connection: Upgrade, HTTP2-Settings
# Upgrade: h2c
# HTTP2-Settings: <base64url encoded SETTINGS>

3. Multiplexing & Stream

Fitur paling revolusioner HTTP/2 adalah multiplexing β€” kemampuan mengirim multiple request dan response secara simultan dalam satu koneksi TCP. Setiap HTTP message dipecah menjadi frames yang di-tag dengan Stream ID, sehingga bisa di-interleave tanpa blocking.

Stream Lifecycle

Text
# Stream States dalam HTTP/2:
#
# idle β†’ open β†’ half-closed β†’ closed
#                (local/remote)
#
# Client-initiated streams: ODD numbers (1, 3, 5, ...)
# Server-initiated streams: EVEN numbers (2, 4, 6, ...)

# Multiplexing dalam aksi:

Client                          Server
  |                               |
  |--- [Stream 1] HEADERS ------>|  (GET /index.html)
  |--- [Stream 3] HEADERS ------>|  (GET /style.css)
  |--- [Stream 5] HEADERS ------>|  (GET /app.js)
  |                               |
  |<-- [Stream 1] DATA ----------|  (HTML response, part 1)
  |<-- [Stream 3] DATA ----------|  (CSS response, part 1)
  |<-- [Stream 1] DATA ----------|  (HTML response, part 2) ← interleaved!
  |<-- [Stream 5] DATA ----------|  (JS response)
  |<-- [Stream 1] DATA END ------|  (HTML selesai)
  |<-- [Stream 3] DATA END ------|  (CSS selesai)
  |<-- [Stream 5] DATA END ------|  (JS selesai)

# Tidak ada Head-of-Line blocking antar stream!
# Satu stream lambat tidak memblokir yang lain.

Stream Priorities dan Dependencies

HTTP/2 memungkinkan client memberikan informasi prioritas pada setiap stream melalui HEADERS atau PRIORITY frame. Ini membantu server mengalokasikan bandwidth secara optimal:

Text
# Priority Tree β€” Contoh halaman web:
#
# Stream 1 (HTML) β€” weight: 256
#   β”œβ”€β”€ Stream 3 (CSS) β€” weight: 220 (paling prioritas!)
#   └── Stream 5 (JS) β€” weight: 183
#       β”œβ”€β”€ Stream 7 (Image 1) β€” weight: 110
#       └── Stream 9 (Image 2) β€” weight: 110

# Priority frame:
# - Exclusive flag: apakah stream eksklusif child?
# - Stream Dependency: parent stream ID (0 = root)
# - Weight: 1-256 (relative weight)

# Strategi browser umum:
# CSS  β†’ Paling tinggi (render-blocking)
# HTML β†’ Tinggi
# JS   β†’ Sedang (parser-blocking tapi bisa defer)
# Font β†’ Sedang-tinggi
# Image β†’ Rendah (lazy-load)
πŸ’‘ RFC 9218: Prioritas Baru (Extensible Priority)

Stream dependency tree terbukti kompleks dan sulit diimplementasikan dengan benar. RFC 9218 menggantikannya dengan sistem prioritas sederhana: urgency (0-7) dan incremental flag (boolean). Ini lebih mudah diimplementasikan oleh server dan lebih predictable.

4. Server Push

Server Push memungkinkan server mengirim resource ke client sebelum client memintanya. Ini berguna untuk resource yang server tahu akan dibutuhkan, seperti CSS, JS, dan font yang direferensikan di HTML.

Alur Server Push

Text
Client                               Server
  |                                    |
  |--- [Stream 1] GET /index.html --->|
  |                                    |
  |<-- [Stream 2] PUSH_PROMISE -------|  (Server push /style.css)
  |    Promised Stream ID: 2           |
  |<-- [Stream 4] PUSH_PROMISE -------|  (Server push /app.js)
  |    Promised Stream ID: 4           |
  |                                    |
  |<-- [Stream 1] DATA (HTML) --------|  (Response untuk index.html)
  |<-- [Stream 2] DATA (CSS) ---------|  (Pushed resource)
  |<-- [Stream 4] DATA (JS) ----------|  (Pushed resource)

# Client bisa MENOLAK push dengan RST_STREAM (CANCEL)
# Pushed resource disimpan di browser cache
# Jika client sudah punya di cache β†’ RST_STREAM β†’ hemat bandwidth

Konfigurasi Server Push di Nginx

Nginx
# nginx.conf β€” HTTP/2 Server Push
server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate /etc/ssl/cert.pem;
    ssl_certificate_key /etc/ssl/key.pem;

    # Aktifkan HTTP/2
    http2_push_preload on;

    location / {
        # Push critical CSS
        http2_push /css/main.css;

        # Push critical JS
        http2_push /js/app.js;

        # Push font
        http2_push /fonts/inter.woff2;

        root /var/www/html;
        index index.html;
    }

    # Alternatif: gunakan Link header untuk push
    location /css/main.css {
        add_header Link "; rel=preload; as=font";
    }
}
⚠️ Server Push: Deprecation Warning

Server Push telah di-deprecate di Chrome (sejak versi 106) dan Safari. Masalah utama: sulit menentukan resource mana yang sudah ada di cache client, sehingga sering terjadi push waste. Alternative yang lebih baik: gunakan 103 Early Hints (RFC 8297) untuk memberitahu browser resource apa yang perlu di-preload.

5. Header Compression (HPACK)

HTTP/1.1 mengirim header dalam format text yang berulang-ulang pada setiap request. Header seperti Cookie, User-Agent, dan Accept yang sama dikirim berulang kali. HPACK (RFC 7541) mengatasi ini dengan kompresi header berbasis Huffman coding dan indexing table.

Cara Kerja HPACK

Text
# HPACK menggunakan dua tabel:

# 1. Static Table (61 entries pre-defined)
#    Index 1:  :authority
#    Index 2:  :method GET
#    Index 3:  :method POST
#    Index 4:  :path /
#    Index 8:  :status 200
#    Index 13: cache-control max-age=0
#    ...dst

# 2. Dynamic Table (berubah selama koneksi)
#    Header yang dikirim client/server ditambahkan ke tabel
#    Index dimulai dari 62 (setelah static table)

# Contoh kompresi:
# Request 1: :method: GET, :path: /api/data, host: example.com, cookie: abc123
# β†’ Encoded dengan static index + Huffman + dynamic table entry

# Request 2: :method: GET, :path: /api/users, host: example.com, cookie: abc123
# β†’ host dan cookie sudah di dynamic table β†’ hanya kirim index reference!

# Penghematan signifikan: dari ~800 bytes menjadi ~50-100 bytes per request

6. QUIC Protocol

QUIC (RFC 9000, 9001, 9002) adalah transport protocol baru yang berjalan di atas UDP, dikembangkan oleh Google dan kemudian distandarisasi oleh IETF. QUIC menggabungkan fungsi transport (TCP), keamanan (TLS), dan multiplexing dalam satu protokol yang dioptimasi untuk web modern.

Mengapa QUIC? Masalah TCP yang Dipecahkan

Masalah TCP Solusi QUIC
Head-of-Line blockingIndependent streams β€” stream A yang lambat tidak blokir stream B
TCP + TLS = 2 RTTHandshake terintegrasi: 1-RTT (atau 0-RTT untuk reconnection)
Connection tied to IPConnection ID — koneksi tetap hidup saat IP berubah (WiFi→LTE)
OS kernel update lambatImplemented di user-space, mudah di-update
TCP congestion control kakuCongestion control yang lebih modern (BBR, CUBIC)

QUIC Connection Establishment

Text
# === TCP + TLS 1.2: 3 RTT ===
Client                               Server
  |--- SYN ----------------------->|  RTT 1: TCP handshake
  |<-- SYN-ACK                     |
  |--- ACK + ClientHello --------->|  RTT 2: TLS handshake
  |<-- ServerHello + Cert          |
  |--- Finished + App Data ------->|  RTT 3: Selesai
  |<-- App Data                    |

# === TCP + TLS 1.3: 2 RTT ===
Client                               Server
  |--- SYN ----------------------->|  RTT 1: TCP + TLS
  |<-- SYN-ACK + ServerHello       |
  |--- ACK + Finished + App Data ->|  RTT 2: Selesai
  |<-- App Data                    |

# === QUIC: 1-RTT (koneksi baru) ===
Client                               Server
  |--- Initial (ClientHello) ----->|  RTT 1: QUIC + TLS terintegrasi
  |<-- Handshake (ServerHello)     |
  |--- 0-RTT App Data ----------->|  (bisa kirim data segera!)

# === QUIC: 0-RTT (koneksi ulang) ===
Client                               Server
  |--- Initial + 0-RTT Data ----->|  ← Data app dikirim SEKARANG
  |<-- Handshake + App Data        |  ← Response dalam 0 RTT!

QUIC Packet Structure

Text
# QUIC Long Header Packet:
#
#  0                   1                   2                   3
#  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
# +-+-+-+-+-+-+-+-+
# |1|1|T|T|X|X|X|X|   Header Form + Type + Reserved
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# |                         Version (32)                           |
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# | DCID Len (8) |  Destination Connection ID (0..160) ...
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# | SCID Len (8) |  Source Connection ID (0..160) ...
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

# QUIC Short Header Packet (1-RTT):
#
# +-+-+-+-+-+-+-+-+
# |0|1|S|R|R|K|P|P|
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# |                Destination Connection ID (0..160) ...
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# |                     Packet Number (1-4 bytes) ...
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# |                    Protected Payload ...
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

7. HTTP/3 di Atas QUIC

HTTP/3 (RFC 9114, 2022) adalah evolusi terbaru dari protokol web yang berjalan di atas QUIC. HTTP/3 mempertahankan semua fitur HTTP/2 (multiplexing, header compression, flow control) tetapi memanfaatkan keunggulan QUIC untuk menghilangkan TCP head-of-line blocking.

Perbandingan HTTP/2 vs HTTP/3

Aspek HTTP/2 HTTP/3
TransportTCP + TLSQUIC (UDP)
Head-of-LineStream-level OK, connection-level blocking di TCPTidak ada HoL blocking
Handshake2 RTT (TCP+TLS) / 1 RTT (TLS 1.3)1-RTT baru / 0-RTT resumption
Header CompressionHPACKQPACK
Connection MigrationTidak (tied ke IP:port)Ya (Connection ID)
EncryptionOptional (TLS di layer terpisah)Wajib (built-in)
Load BalancingStandard TCP load balancerPerlu QUIC-aware LB

Mengapa QPACK, Bukan HPACK?

HPACK bergantung pada ordered delivery β€” header yang dikirim harus diterima dalam urutan yang sama untuk menjaga dynamic table sinkron. Dengan QUIC yang mendukung independent stream delivery, HPACK tidak bisa langsung digunakan. QPACK (RFC 9204) menyelesaikan ini dengan memisahkan encoding dan decoding stream.

Text
# QPACK Architecture:

# Encoder Stream  (client β†’ server)
#   β†’ Mengirim dynamic table insertions
#   β†’ Mengirim header acknowledgments

# Decoder Stream  (server β†’ client)
#   β†’ Mengirim table size updates
#   β†’ Mengirim insert count increments

# Request/Response Stream
#   β†’ Menggunakan encoded header blocks
#   β†’ Bisa reference static + dynamic table
#   β†’ Bisa deferred: tunggu table update jika perlu

# Contoh QPACK encoded header:
# Required Insert Count: 5
# Base: 3
# Encoded Fields:
#   Literal with Name Reference (static index 1 β†’ :authority)
#   Indexed (dynamic index 64 β†’ content-type: application/json)
#   Literal with Name Reference (static index 26 β†’ content-length)

Connection Migration

Text
# Connection Migration β€” salah satu fitur terbaik HTTP/3 + QUIC
#
# Ketika device berpindah jaringan (WiFi β†’ cellular), IP berubah.
# Dengan TCP: koneksi terputus, harus reconnect + re-handshake.
# Dengan QUIC: koneksi tetap hidup via Connection ID.

Device (WiFi)           Server
  |                       |
  |--- [CID=abc123] ----->|  ← Normal traffic via WiFi
  |<-- [CID=abc123] ------|
  |                       |
  ... Device pindah ke LTE, IP berubah ...
  |                       |
  |--- [CID=abc123] ----->|  ← Sama CID, IP baru!
  |<-- [CID=abc123] ------|  ← Server mengenali via CID
  |                       |     (tidak perlu re-handshake!)

8. Tips Optimasi Performa

Best Practices HTTP/2

πŸ’‘ Domain Sharding: Stop Melakukannya

Di HTTP/1.1, developer menggunakan domain sharding (assets1.example.com, assets2.example.com) untuk mengatasi limit 6 koneksi per domain. Di HTTP/2, ini kontraproduktif β€” setiap domain butuh koneksi terpisah, menghilangkan manfaat multiplexing dan connection reuse. Gunakan satu domain saja!

Optimasi Resource Loading

HTML
<!-- ❌ HTTP/1.1 style: domain sharding (JANGAN di HTTP/2) -->
<link rel="stylesheet" href="https://cdn1.example.com/style.css">
<script src="https://cdn2.example.com/app.js"></script>

<!-- βœ… HTTP/2+ style: single connection, resource hints -->
<link rel="preconnect" href="https://cdn.example.com">
<link rel="preload" href="/fonts/inter.woff2" as="font" crossorigin>
<link rel="preload" href="/css/critical.css" as="style">
<link rel="preload" href="/js/app.js" as="script">

<!-- βœ… 103 Early Hints (modern alternative to server push) -->
<!-- Server mengirim header: -->
<!-- HTTP/1.1 103 Early Hints -->
<!-- Link: </css/style.css>; rel=preload; as=style -->
<!-- Link: </js/app.js>; rel=preload; as=script -->

<!-- βœ… Tekan ukuran header untuk performa -->
<!-- Cookie kecil, hapus header yang tidak perlu -->
<!-- Gunakan HPACK-aware CDN -->

Mengecek HTTP Versi yang Digunakan

Bash
# Cek HTTP version menggunakan curl
curl -sI --http2 https://www.google.com 2>/dev/null | head -5
# HTTP/2 200
# content-type: text/html; charset=ISO-8859-1

curl -sI --http3 https://www.google.com 2>/dev/null | head -5
# HTTP/3 200
# content-type: text/html; charset=ISO-8859-1

# Cek dengan verbose
curl -v --http2 https://example.com 2>&1 | grep -i "ALPN\|HTTP/"
# * ALPN: server accepted h2
# < HTTP/2 200

# Di browser: buka DevTools β†’ Network β†’ klik kanan kolom
# β†’ aktifkan "Protocol" column
# Tampilkan: h2, h3, http/1.1

# Menggunakan httpstat untuk analisis lebih detail
go install github.com/davecheney/httpstat@latest
httpstat https://www.google.com

Quiz Pemahaman

Pertanyaan 1: Apa masalah utama yang diselesaikan oleh multiplexing di HTTP/2?

a) Enkripsi data
b) Head-of-Line blocking
c) Kompresi gambar
d) Caching otomatis

Pertanyaan 2: Berapa RTT yang dibutuhkan QUIC untuk koneksi baru?

a) 3 RTT
b) 2 RTT
c) 1 RTT
d) 4 RTT

Pertanyaan 3: Mengapa QPACK menggantikan HPACK di HTTP/3?

a) QPACK lebih cepat 10x
b) HPACK memerlukan ordered delivery yang tidak dijamin oleh QUIC streams
c) QPACK menggunakan enkripsi
d) HPACK sudah tidak didukung browser

Pertanyaan 4: Mengapa domain sharding kontraproduktif di HTTP/2?

a) Karena DNS lambat
b) Karena setiap domain butuh koneksi terpisah, menghilangkan manfaat multiplexing
c) Karena cookie tidak bisa dibagikan
d) Karena browser membatasi domain

Pertanyaan 5: Fitur QUIC apa yang memungkinkan koneksi tetap hidup saat IP berubah?

a) Stream multiplexing
b) 0-RTT resumption
c) Connection ID
d) QPACK compression
πŸ” Zoom
100%
🎨 Tema