Lesson 02: Path & Host Routing Mechanics

ผ่าตัดกลไกการจับคู่คำขอ (Routing Engine) ของ Kong Gateway: เจาะลึกความแตกต่างระหว่าง strip_path, การรักษาโดเมนด้วย preserve_host, กฎลำดับความสำคัญของ Prefix Tree และการใช้ Regular Expressions

✦ 1. บทนำสู่กลไก Routing: ทำไมต้องคุมการส่งต่อ Path & Host?

สรุปใจความสำคัญในประโยคเดียว:
Routing Mechanics คือกฎเกณฑ์และกลไกแปลงสภาพ HTTP Request หน้าบ้านของ Client เพื่อส่งต่อไปยังเซิร์ฟเวอร์หลังบ้าน โดยควบคุมว่า Path จะถูกตัดแต่งอย่างไร และ Host Header ใดจะถูกส่งต่อ

ปัญหาโลกจริง: ปลายทางหน้าบ้านกับหลังบ้าน "พูดคนละภาษา"

ในโลกของ Microservices สถาปัตยกรรม URL ของผู้ใช้ภายนอก (Public API) มักถูกออกแบบให้เป็นระเบียบ เช่น:
https://api.company.com/v1/orders/123

แต่เซิร์ฟเวอร์หลังบ้าน (Internal Order Service) กลับถูกเขียนให้รับ Request แค่:
http://order-pod:8080/orders/123 หรือแม้กระทั่ง http://order-pod:8080/123

หากไม่มีตัวแปลง Path ที่ชาญฉลาด วิศวกรจะต้องเขียนโค้ดหลังบ้านเพื่อรองรับ Prefix ของทุกเวอร์ชัน หรือต้องคอยแก้ Route ในโค้ดทุกครั้งที่มีการเปลี่ยนโดเมน นอกจากนี้ หากระบบหลังบ้านเป็นระบบที่อาศัยโดเมนเนมในการแยกแยะ Tenant (Multi-tenant SaaS) แต่ Gateway ดันส่ง Hostname ภายในไปแทน ระบบหลังบ้านจะตอบกลับเป็น Error 404 หรือ Access Denied ทันที

นี่คือเหตุผลที่ Kong Gateway มีพารามิเตอร์แกนกลาง 2 ตัว ได้แก่ strip_path และ preserve_host เพื่อทำหน้าที่เป็น "ตัวเชื่อมและแปลงสาร" อย่างสมบูรณ์แบบ

✦ 2. Formal Glossary & Conceptual Foundations

เพื่อความแม่นยำทางวิศวกรรม ตารางด้านล่างนี้นิยามพารามิเตอร์และกลไกของ Router ตามข้อกำหนด Kong Core Routing Specification:

พารามิเตอร์ / กลไก นิยามทางการ (Formal Definition) หน้าที่หลัก (Primary Purpose) ขอบเขตและความแตกต่าง (Distinction)
strip_path Boolean flag บน Route Entity ที่ควบคุมการตัด Prefix Path ส่วนที่ Match ออกจาก URI ซ่อนพาธภายนอก (Public Prefix) ไม่ให้ถูกส่งต่อเข้าสู่ Internal Path ของ Service หลังบ้าน หากเป็น true Prefix ที่ Match จะหายไป แล้วนำเศษที่เหลือไปต่อท้าย Service.path; หากเป็น false Path เดิมของ Client จะถูกส่งไปทั้งยวง
preserve_host Boolean flag บน Route Entity ที่กำหนดว่าให้รักษา HTTP Host Header เดิมของ Client หรือไม่ ช่วยให้ระบบ Multi-Tenant หรือ Virtual Hosting หลังบ้าน สามารถแยกแยะ Domain เดิมของผู้ใช้ได้ หากเป็น false (Default) Kong จะแทนที่ Host ด้วย Hostname ของ Service/Upstream; หากเป็น true จะส่ง Host เดิมของ Client เสมอ
Prefix Tree Router โครงสร้างข้อมูล Radix Tree ในหน่วยความจำของ Kong Router Engine สำหรับจับคู่ Path ตามความยาว ค้นหา Route ที่ตรงกับคำขอด้วยความเร็วระดับ $O(k)$ (เมื่อ $k$ คือความยาวของ Path) จับคู่แบบ Longest Prefix Match เสมอ โดย Route ที่มี Path ยาวและเจาะจงกว่าจะชนะ Route ที่สั้นกว่า
Regex Path (~) รูปแบบ Path ที่ขึ้นต้นด้วยสัญลักษณ์ตัวหนอน (~) สั่งให้ใช้ PCRE Engine ในการจับคู่ รองรับการจับคู่แบบ Dynamic Pattern เช่น ตัวเลขรหัสบัตร, UUID, หรือ Path Variables ประมวลผลช้ากว่า Prefix Match เล็กน้อย และต้องระวังเรื่อง Regular Expression Denial of Service (ReDoS)
Route Priority ลำดับการประเมินผลคำขอเมื่อมี Route หลายตัวที่ Match ได้พร้อมกัน กำหนดว่า Request จะถูกส่งเข้า Service ใดอย่างแม่นยำ (Deterministic) ไม่มีการสุ่ม เรียงจาก: จำนวน Match Rules (Headers + Hosts + Paths) ➔ Longest Path Prefix ➔ Regex Evaluation Order

✦ 3. Real-World Engineering War Story & Case Study

🚨 เหตุการณ์จริง: "The Great Multi-Tenant Routing Meltdown"
องค์กร: แพลตฟอร์ม Enterprise HR & Payroll SaaS (ผู้ใช้งานองค์กรกว่า 2,400 บริษัท)
ความเสียหาย: ระบบคลังข้อมูลพนักงานแสดงผลผิดบริษัท (Data Leaks) และระบบจ่ายเงินเดือนล้มเหลว 85 นาที

จุดเริ่มต้นของความผิดพลาด: ทีมงานทำการย้ายระบบ (Migration) จาก Nginx แบบเดิมมาใช้ Kong Gateway เพื่อจัดการ Route เข้าสู่ระบบแกนกลาง Multi-tenant Core Service สถาปัตยกรรมหลังบ้านใช้ HTTP Host Header ในการตรวจสอบว่าคำขอนั้นเป็นของบริษัทใด เช่น:
• acme.hr-saas.com ➔ ตรวจสอบเข้าฐานข้อมูลของบริษัท ACME Corp
• globex.hr-saas.com ➔ ตรวจสอบเข้าฐานข้อมูลของบริษัท Globex

วินาทีที่ระบบล่ม: ในการเขียนคอนฟิก `kong.yml` ทีมวิศวกรลืมกำหนดพารามิเตอร์ preserve_host: true (ซึ่ง Kong มีค่าเริ่มต้นเป็น false) ส่งผลให้ Kong ทำการเขียนทับ (Overwrite) Header Host ของทราฟฟิกทั้งหมดให้กลายเป็นชื่อ Upstream ภายใน:
Host: hr-core-upstream.internal:8080

เมื่อคำขอวิ่งไปถึง Backend Service ระบบหลังบ้านหาชื่อบริษัท hr-core-upstream.internal ในฐานข้อมูลไม่พบ จึงตอบกลับเป็น HTTP 404 Tenant Not Found ไปยังพนักงานกว่า 120,000 คนทั่วโลก พร้อมทั้งบางส่วนที่ระบบ Fallback ดึงคอนฟิก Default Tenant ส่งผลให้พนักงานเห็นข้อมูลแผนกของบริษัทอื่น!

การกู้ภัยด้วย Kong Configuration: ทีม Incident Commander สั่งปรับแก้คอนฟิก Declarative `kong.yml` โดยเติม preserve_host: true และสั่ง deck sync ภายใน 3 วินาที Traffic ทั้งหมดได้รับการฟื้นฟู และนี่คือบทเรียนราคาแพงว่า การเข้าใจค่า Default ของ Host และ Path Routing คือหัวใจของความปลอดภัยระดับองค์กร

✦ 4. Mental Model & Architecture Data Flow

อุปมาอุปไมย: "ศูนย์กระจายพัสดุนานาชาติ (The International Mail Depot)"

ลองเปรียบเทียบการทำงานของ Kong Router กับขั้นตอนการคัดแยกพัสดุ:

Routing Decision & Transformation Pipeline

CLIENT REQUEST Host: tenant.acme.com URI: /api/v1/users/42 GET Method KONG ROUTER ENGINE (In-Memory Radix Tree) ROUTE MATCHING paths: ["/api/v1"] strip_path: true preserve_host: false Longest Prefix Match ✓ SERVICE host: user-service path: /internal port: 8080 UPSTREAM BACKEND Host: user-service:8080 URI: /internal/users/42 Prefix /api/v1 ตัดทิ้งสำเร็จ

✦ 5. Hands-on Syntax Breakdown & Implementation (3 Levels)

Anatomy Breakdown: โครงสร้างคอนฟิก Route Specification

_format_version: "3.0"

services:
  - name: inventory-service
    url: http://inventory-backend:8080/v2/items # Base URL และ Default Path
    routes:
      - name: inventory-route
        paths:
          - /store/inventory                    # [1] URI Prefix ที่ต้องการดักจับ
        strip_path: true                        # [2] ตัด /store/inventory ออกก่อนส่งต่อ
        preserve_host: true                     # [3] ส่ง Host Header เดิมของ Client ไปยัง Backend
        methods:
          - GET                                 # [4] ดักเฉพาะ HTTP Methods ที่ระบุ
          - POST
        hosts:
          - "*.company.com"                     # [5] Wildcard Host Matching
        protocols:
          - http
          - https

Level 1 (Beginner): พื้นฐาน Path Routing & strip_path

การแมปเบื้องต้นเพื่อตัด Prefix ภายนอกออกจาก API โดยส่งต่อไปยัง Backend ที่ไม่มี Prefix:

_format_version: "3.0"

services:
  - name: simple-catalog-service
    url: http://catalog-pod:8080/products
    routes:
      - name: catalog-public-route
        paths:
          - /api/catalog
        strip_path: true    # /api/catalog/detail/10 ➔ http://catalog-pod:8080/products/detail/10

Level 2 (Intermediate): Host-Based Routing & Multi-Tenant Support

การแยกเส้นทางตามโดเมนเนม (Host-based Routing) ควบคู่กับ Path โดยเปิดใช้งาน preserve_host:

_format_version: "3.0"

services:
  - name: enterprise-tenant-service
    url: http://tenant-cluster:8080
    routes:
      - name: tenant-alpha-route
        hosts:
          - alpha.saas-platform.com
        paths:
          - /portal
        strip_path: false   # ส่ง /portal ไปยังหลังบ้านด้วย
        preserve_host: true # Backend ได้รับ Host: alpha.saas-platform.com นำไป Query DB ต่อได้ถูกบริษัท

Level 3 (Production-Grade): Priority Order & Regex Path Matching

Anti-Pattern ที่พบบ่อย: วาง Route ที่เป็น General Prefix (เช่น /api) ไว้โดยไม่คุม Priority ทำให้ไปบังคับกลืน Route ที่เป็น Regex หรือ Route ที่มีความเจาะจงสูงกว่า

Production Solution: ใช้งาน Regex Matching ด้วยตัวหนอน ~ พร้อมจัดสรร Priority และดักจับ Query Parameters:

_format_version: "3.0"

services:
  - name: legacy-api-service
    url: http://legacy-core:8080/app
    routes:
      # Route เจาะจง: Regex จับคู่เฉพาะ Version 1 ถึง Version 3 ที่มีตัวเลข ID
      - name: strict-versioned-route
        paths:
          - ~/api/v[1-3]/accounts/\d+
        strip_path: false
        preserve_host: true
        protocols:
          - https

  - name: fallback-api-service
    url: http://fallback-handler:8080
    routes:
      # Route ทั่วไป: จะถูกเลือกเฉพาะเมื่อไม่ตรงกับ Regex ด้านบน (Longest Prefix Match Rules)
      - name: general-api-route
        paths:
          - /api
        strip_path: true
        protocols:
          - https

✦ 6. Interactive Simulator: Path & Host Transformation Engine

ทดลองป้อน Request ของ Client และปรับแต่งค่า strip_path, preserve_host เพื่อดูผลลัพธ์แบบเรียลไทม์ว่า Kong Router จะส่ง Request หน้าตาอย่างไรไปถึง Backend จริง:

สถานะการ Match (Route Match Status): MATCHED SUCCESS ✓
Forwarded Host Header (ที่ Backend ได้รับ): order-backend:8080
Forwarded Full URI (ที่ Backend ได้รับ): http://order-backend:8080/internal/orders/789
สรุปการแปลง Path: ตัด prefix '/api/v1' ออก เหลือ '/orders/789' นำไปต่อท้าย '/internal'

✦ 7. Active Recall Deep-Dive Exam (20 ข้อ: เนื้อหา Day 02 + Spaced Repetition จาก Day 01)

แบบทดสอบจำนวน 20 ข้อ จัดสัดส่วนตามหลัก Spaced Repetition: ข้อ 1-15 เจาะลึก Path & Host Routing Mechanics ของ Day 02 และ ข้อ 16-20 คือ Spaced Repetition Review ดึงทบทวน 4 เสาหลักและ Health Checks จาก Day 01 เพื่อตอกย้ำความจำระยะยาว

ความคืบหน้า: ตอบแล้ว 0 / 20 ข้อ
คะแนนรวม: 0 / 20