Chuyển đến nội dung chính

Lesson 7: HTTP/HTTPS & HTTP/2

http.createServer, routing, middleware pattern from scratch. HTTPS/TLS setup. HTTP/2 server push. Request/Response handling, chunked transfer. Keep-alive, connection pooling.

💻 Programming — Lesson 7 Lesson 7: HTTP/HTTPS & HTTP/2

Node.js Core: From Basics to Advanced

Part 2: Core Modules Deep Dive

xdev.asia

1. Basic HTTP Server

import { createServer, IncomingMessage, ServerResponse } from 'node:http'

const server = createServer((req: IncomingMessage, res: ServerResponse) => {
  // Request info
  const { method, url, headers } = req
  console.log(`${method} ${url}`)

  // Routing cơ bản
  if (method === 'GET' && url === '/') {
    res.writeHead(200, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({ message: 'Hello World' }))
  } else if (method === 'GET' && url === '/health') {
    res.writeHead(200)
    res.end('OK')
  } else {
    res.writeHead(404)
    res.end('Not Found')
  }
})

server.listen(3000, () => console.log('Server on :3000'))

2. Read Request Body

async function parseBody(req: IncomingMessage): Promise<unknown> {
  const chunks: Buffer[] = []
  for await (const chunk of req) {
    chunks.push(chunk as Buffer)
  }
  const body = Buffer.concat(chunks).toString()
  const contentType = req.headers['content-type'] || ''

  if (contentType.includes('application/json')) {
    return JSON.parse(body)
  }
  return body
}

// Sử dụng
const server = createServer(async (req, res) => {
  if (req.method === 'POST' && req.url === '/api/users') {
    const body = await parseBody(req) as { name: string }
    res.writeHead(201, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({ id: 1, name: body.name }))
  }
})

3. HTTPS/TLS Server

import { createServer } from 'node:https'
import { readFileSync } from 'node:fs'

const server = createServer({
  key: readFileSync('certs/private-key.pem'),
  cert: readFileSync('certs/certificate.pem'),
  ca: readFileSync('certs/ca.pem'),
}, (req, res) => {
  res.writeHead(200)
  res.end('Secure!')
})

server.listen(443)

4. HTTP/2 Server

import { createSecureServer } from 'node:http2'
import { readFileSync } from 'node:fs'

const server = createSecureServer({
  key: readFileSync('certs/key.pem'),
  cert: readFileSync('certs/cert.pem'),
  allowHTTP1: true,
})

server.on('stream', (stream, headers) => {
  const path = headers[':path']
  const method = headers[':method']

  stream.respond({
    'content-type': 'application/json',
    ':status': 200,
  })
  stream.end(JSON.stringify({ path, method, protocol: 'h2' }))
})

server.listen(8443)

5. fetch (Built-in)

// Node.js 22+ — fetch là global (dựa trên undici)
const response = await fetch('https://api.github.com/users/octocat', {
  headers: { 'User-Agent': 'Node.js' },
  signal: AbortSignal.timeout(5000), // Timeout 5s
})

if (!response.ok) throw new Error(`HTTP ${response.status}`)
const data = await response.json()

6. Connection Pooling

import { Agent } from 'node:http'

// Custom agent với connection pooling
const agent = new Agent({
  keepAlive: true,
  keepAliveMsecs: 30000,
  maxSockets: 50,
  maxFreeSockets: 10,
})

// Dùng với fetch (undici)
import { Agent as UndiciAgent, setGlobalDispatcher } from 'undici'

setGlobalDispatcher(new UndiciAgent({
  connections: 50,
  pipelining: 10,
  keepAliveTimeout: 30000,
}))

Next article: Crypto, OS & Process — hashing, encryption, child processes.