ทดลองสร้าง HTTP/2 Server Push ด้วย Node.js

October 26, 2023 (1y ago) 71 views

การทำงานของ Server Push และสร้างแอปเพื่อใช้งานความสามารถของ Server Push โดยใช้ Node.js ครับ

หลังจากที่ HTTP/2 ได้เปิดตัวตั้งแต่ปี 2015 และได้รับการพิสูจน์แล้วว่า การใช้ HTTP/2 สามารถลด Latency Time ได้จริง ด้วย Features ต่างๆ ของ HTTP/2 ดังนี้

  • Binary: ปรับค่าต่างๆ ให้อยู่ในรูปแบบ Binary แทนที่จะเป็นข้อความธรรมดา
  • Multiplexed: สามารถส่ง Request ได้หลายครั้งภายใต้ TCP Connection เพียงอันเดียว เช่น Browser ขอไฟล์ 3 ไฟล์จาก Server ถ้าเป็น HTTP/1 ก็จะใช้ 3 Connection แต่ถ้าเป็น HTTP/2 ก็จะใช้เพียง Connection เดียว
  • Header Compression: บีบอัดขนาดของ Header โดยใช้ HPACK
  • Server Push: ส่งข้อมูลหรือ Response อะไรบางอย่างไปยัง Client โดยไม่ต้องรอ Request เดี๋ยวจะพูดถึงเรื่องนี้อีกทีด้านล่างนะครับ

โดยในบทความนี้ผมจะมาพูดถึงเรื่องการทำงานของ Server Push และสร้างแอปเพื่อใช้งานความสามารถของ Server Push โดยใช้ Node.js ครับ

HTTP/2 Server push คืออะไร?

คือการที่ Server ส่งข้อมูลหรือ Response อะไรบางอย่างกลับไปยัง Client ให้เลยโดยไม่ต้องรอ Request จาก Client ประมาณว่าถ้า Client ขอไฟล์ index.html จาก Server แล้ว Server ก็รู้ว่าเดี๋ยวมันจะต้องขอ styles.css และ app.js ต่อแน่ๆ แทนที่จะรอให้ Client ขอไฟล์ Server ก็จัดการ Response styles.css และ app.js ไปพร้อมกลับ index.htmlเลย

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello HTTP/2</title>
    <link rel="stylesheet" href="/app.css" media="all">
  </head>
  <body>
    <h1>Hello HTTP/2</h1>
    <script src="app.js"/></script>
  </body>
</html>

ถ้าแบบปกติที่ไม่ใช้ Server Push นะครับ เมื่อ User เข้า Web Browser /index.html หน้าตาของการปฏิสัมพันธ์กันระหว่าง Client กับ Server จะเป็นแบบนี้ครับ

choc-factory

ตัวอย่างการสื่อสารระหว่าง Web Browser กับ Server ที่ไม่ใช้ HTTP/2 Server Push

และนี้ก็เป็นแบบปกติทั่วไปนะครับ ที่เราใช้เว็บกันอยู่ทุกวันมันก็ดู Make Sense ใช่ไหมครับ แล้วปัญหามันคืออะไรล่ะ?

ปัญหาก็คือ User ต้องรอจนกว่า Web Browser จะ Render หน้า index.html เสร็จ และค้นหาบรรทัดที่ต้องโหลดไฟล์ styles.css และ app.js ให้เจอ Browser จึงจะทำการขอไฟล์ styles.css และ app.js ต่อไป ก็อาจจะเป็นปัญหาให้การ render หน้าเว็บช้าหรือว่าเพิ่ม Load time ได้

และปัญหานี้ก็ก่อให้เกิด HTTP/2 Server Push ที่มากับความสามารถในการส่ง Asset ไฟล์ไปยัง Client เลย โดยไม่จำเป็นต้องรอ Request จาก Client

ถ้า User เข้า Web Browser /index.html โดยมีการใช้ HTTP/2 Server Push หน้าตาของการปฏิสัมพันธ์กันระหว่าง Client กับ Server จะเป็นแบบนี้ครับ

choc-factory

ตัวอย่างการสื่อสารระหว่าง Web Browser กับ Server ที่ใช้ HTTP/2 Server Push

ต่อไปเดี๋ยวลองไปดูตัวอย่างการ HTTP/2 Server Push ที่เป็นโค้ดนะครับ

ตัวอย่าง HTTP/2 Server Push ใน Node.js

(เวอร์ชั่นที่ใช้ในตัวอย่างคือ Node.js v10.2.1)

server.js
'use strict'
 
const http2 = require('http2')
const fs = require('fs')
const path = require('path')
const helper = require('./helper')
 
const { HTTP2_HEADER_PATH } = http2.constants
const PUBLIC_PATH = path.join(__dirname, '../public')
const SSL_PATH = path.join(__dirname, '../ssl')
 
const publicFiles = helper.getFiles(PUBLIC_PATH)
 
function push(stream, path) {
  const file = publicFiles.get(path)
  if (!file) {
    return
  }
  stream.pushStream(
    { [HTTP2_HEADER_PATH]: path },
    { parent: stream.id },
    (err, pushStream, headers) => {
      if (err) throw err
      pushStream.respondWithFD(file.fileDescriptor, file.headers)
    }
  )
}
 
const server = http2.createSecureServer({
  key: fs.readFileSync(SSL_PATH + '/server.key'),
  cert: fs.readFileSync(SSL_PATH + '/server.crt'),
})
 
server.on('stream', (stream, headers) => {
  console.log(headers[':path'])
  const reqPath = headers[':path'] === '/' ? '/index.html' : headers[':path']
  const file = publicFiles.get(reqPath)
 
  if (!file) {
    stream.statusCode = 404
    stream.end()
    return
  }
 
  if (reqPath === '/index.html') {
    push(stream, '/styles.css')
    push(stream, '/app.js')
  }
 
  stream.respondWithFD(file.fileDescriptor, file.headers)
})
 
server.on('error', err => console.error(err))
 
server.listen(3030)

Run Server โดยพิมพ์คำสั่ง

node server.js --expose-http2

จากนั้นใช้ Web Browser เปิดไปที่ https://localhost:3030

แค่นี้เราก็จะสามารถใช้ความสามารถของ HTTP/2 Server Push ได้แล้ว หากต้องการดูโค้ดแบบเต็มๆ สามารถดูได้ที่ GitHub เลยครับ https://gist.github.com/dumpsayamrat

จะรู้ได้อย่างไรว่ามีการใช้งาน HTTP/2 Server Push หรือไม่

อันดับแรกต้องทำให้แน่ใจก่อน SSL Certificate ที่ใช้ Secure ก่อนนะครับ ไม่อย่างนั้น Google Chrome จะไม่ยอมให้ใช้งาน Server Push

นี่คือวิธีทำให้ localhost ใช้งาน HTTPS ได้ (สำหรับ Mac)

ต่อมาให้เปิด Developer Tools ไปที่แท็บ Network

choc-factory
แบบธรรมดา ไม่ใช้ HTTP/2 Server Push
choc-factory
แบบใช้ HTTP/2 Server Push

ข้อแตกต่างระหว่างใช้กับไม่ใช้ HTTP/2 Server Push คือ ในช่อง Initiator ถ้าใช้จะแสดง Push / index.html ของแต่ละไฟล์ และ ช่อง Waterfall ถ้าใช้จะไม่มีแท็บสีเขียวเลย

ผมก็หวังบทความนี้จะเป็นประโยชน์ไม่มากก็น้อยสำหรับทุกคนนะครับ ขอบคุณมากครับ