คู่มือพิมพ์เขียวเชิงลึกและการวิเคราะห์ทางเทคนิค: การเปลี่ยน MockServer เป็นด่านตรวจกลางสาย, ถอดรหัส HTTPS ด้วย Root CA, สกัดทราฟฟิกจริงสู่ Mocks และการดักแก้ไข Payload กลางอากาศ
ชื่อบท/หัวข้อหลัก: Module 3: Proxying (Forward, Web, HTTPS Tunneling with Root CA), Record & Replay, and Interactive Breakpoints
ตอบ: ในชีวิตการทำงานจริง เราต้องทำงานร่วมกับระบบภายนอก (Third-party APIs) หรือ Legacy Systems ที่ไม่มีเอกสาร API (API Spec) หรือเอกสารเก่าไม่อัปเดต การนั่งเดา Payload หรือพิมพ์ JSON Mocks ด้วยมือทีละข้อจะเสียเวลาและเสี่ยงต่อความผิดพลาด บทนี้ตั้งชื่อว่า Proxying, Record & Replay, and Interactive Breakpoints เพราะ MockServer สามารถทำหน้าที่เป็น Proxy (คั่นกลางบนสายเคเบิล) เพื่อแอบส่องและบันทึกทราฟฟิกจริง (Record) นำมาแปลงเป็น Mocks อัตโนมัติ (Replay) และยังเปิดโอกาสให้ดักแก้ไขทราฟฟิกกลางอากาศ (Interactive Breakpoints) ช่วยให้แกะรอยและสร้าง Mocks จากระบบจริงได้อย่างแม่นยำ 100% โดยไม่ต้องเดา
การเชื่อมต่อ Legacy Payment Gateway อายุ 15 ปี ที่ไม่มี API Documentation
บริษัทสตาร์ทอัปแห่งหนึ่งต้องเชื่อมต่อระบบชำระเงินเข้ากับธนาคารท้องถิ่นรายหนึ่ง ซึ่งใช้ระบบโบราณ เอกสาร API ที่ธนาคารให้มาเป็นไฟล์ PDF ที่อัปเดตครั้งสุดท้ายเมื่อปี 2010 เมื่อทีมวิศวกรพยายามเขียน Mocks ตามเอกสาร PDF ผลคือยิงทดสอบไม่เคยผ่าน เพราะเซิร์ฟเวอร์จริงของธนาคารมีการส่ง Custom Headers และลับโครงสร้าง JSON ไม่ตรงกับเอกสาร
ทีมงานไม่สามารถนั่งเดาโครงสร้าง Request/Response ได้อีกต่อไป และสภาพแวดล้อม Sandbox ของธนาคารก็อนุญาตให้ยิงทดสอบได้เฉพาะช่วงเวลา 01:00 - 03:00 น. เท่านั้น
💡 การนำ Proxying & Record/Replay เข้ามาแก้ปัญหา: ทีมงานเปิด MockServer ทำหน้าที่เป็น HTTPS Tunneling Proxy คั่นกลางระหว่างแอปพลิเคชันทดสอบกับ Sandbox ของธนาคาร ในช่วงเวลา 01:00 น. ทีมงานสั่งรัน Test Flow เพียงครั้งเดียว ให้ทราฟฟิกวิ่งผ่าน MockServer Proxy ซึ่งทำการสกัดรหัส SSL ผ่าน Dynamic Root CA Certificate และเก็บบันทึกทราฟฟิกทั้งหมดไว้ (Record) จากนั้นสั่งให้ MockServer แปลงบันทึกทราฟฟิกนั้นให้กลายเป็น Expectation JSON อัตโนมัติ (Replay) รัน Integration Test ได้ตลอด 24 ชั่วโมง โดยไม่ต้องง้อ Sandbox ของธนาคารอีกเลย!
แปลตรงตัว: การตั้งเซิร์ฟเวอร์คั่นกลางเพื่อส่งผ่านและส่องดูข้อมูล
อุปมาอุปไมย: เหมือน "ด่านตรวจทางด่วน" ที่รถทุกคันต้องวิ่งผ่าน เจ้าหน้าที่ด่านตรวจสามารถมองเห็นป้ายทะเบียน และของที่บรรทุกอยู่ในรถ (Headers & Payload) ก่อนปล่อยให้รถวิ่งต่อไปยังปลายทาง
แปลตรงตัว: การอุโมงค์เชื่อมต่อแบบปลอดภัยโดยใช้ใบรับรอง Root CA ไดนามิก
อุปมาอุปไมย: เหมือน "ตู้ขนส่งความปลอดภัยสูงที่ใช้กระจกใสพิเศษ" ปกติการส่งข้อมูล HTTPS จะเหมือนรถขนเงินที่ปิดมิดชิดมองไม่เห็นข้างใน แต่ MockServer จะใช้ใบรับรอง Root CA พิเศษเปรียบเหมือนแว่นตาเอกซเรย์ ทำให้สามารถมองเห็นเนื้อหาข้อมูลภายในอุโมงค์ HTTPS ได้
แปลตรงตัว: การบันทึกทราฟฟิกแล้วนำกลับมาจำลองซ้ำ
อุปมาอุปไมย: เหมือน "การกดอัดเทปเสียงร้องเพลง" เมื่อยิง Request จริงผ่าน Proxy ครั้งแรก ม้วนเทปจะอัดเสียงไว้ (Record) หลังจากนั้นกดปุ่มเล่นเทป (Replay) เสียงเพลงเดิมก็จะเล่นออกมาทันที
แปลตรงตัว: จุดหยุดพักเพื่อแก้ไขข้อมูลสดกลางอากาศ
อุปมาอุปไมย: เหมือน "ด่านศุลกากรที่สั่งกักรถชั่วคราว" เมื่อ Request วิ่งเข้ามา ด่านจะกักรถไว้แล้วเปิดโอกาสให้เราเข้าไปแก้ไขสิ่งของในท้ายรถ (ปรับแก้ JSON Body หรือ Status Code สดๆ) ก่อนปล่อยให้รถวิ่งต่อไปยังจุดหมาย
การเสียเวลาพัฒนาซอฟต์แวร์ไปกับการ Guessing API Contracts (เดาสเปก API เอง) เนื่องจากเอกสารไม่อัปเดต หรือไม่มี Sandbox ให้ใช้ตลอดเวลา
ชิ้นงานเสร็จล่าช้ากว่ากำหนด (Project Delay), เกิด Bug บน Production จากการที่ Mocks ไม่ตรงกับพฤติกรรมจริงของ Third-party และเสียค่าใช้จ่ายในการเข้าใช้ Sandbox
PUT /mockserver/retrieve)
# [Line 1] ส่งคำสั่ง PUT ไปยัง Endpoint /mockserver/retrieve พร้อมระบุ query parameter type=EXPECTATIONS
curl -X PUT "http://localhost:1080/mockserver/retrieve?type=EXPECTATIONS"
# โครงสร้าง JSON ผลลัพธ์ที่ MockServer สกัดออกมาให้อัตโนมัติ:
[
{
"httpRequest": {
"method": "POST",
"path": "/api/v1/payments",
"headers": { "Host": ["api.bank.com"], "Content-Type": ["application/json"] },
"body": "{\"amount\": 500, \"currency\": \"THB\"}"
},
"httpResponse": {
"statusCode": 200,
"headers": { "Content-Type": ["application/json"] },
"body": "{\"status\": \"SUCCESS\", \"transactionId\": \"TX-998811\"}"
}
}
]
httpForward)
{
"httpRequest": { // [Section 1] ดักจับ Request ที่ยิงเข้ามาหา Path /forward-test
"method": "POST",
"path": "/forward-test"
},
"httpForward": { // [Section 2] สั่งให้ MockServer ทำหน้าที่เป็น Reverse Proxy ส่งต่อ
"host": "httpbin.org", // ระบุ Host ปลายทางที่จะส่งต่อ Request ไป
"port": 80, // ระบุพอร์ตปลายทาง (80 สำหรับ HTTP, 443 สำหรับ HTTPS)
"scheme": "HTTP" // ระบุโปรโตคอล (HTTP หรือ HTTPS)
}
}
PUT /mockserver/verifySequence)
{
"httpRequests": [ // [Section 1] กำหนดอาร์เรย์ของ Request ที่ต้องเกิดขึ้นเรียงตามลำดับ
{
"method": "POST",
"path": "/api/v3/init" // ขั้นตอนที่ 1: ต้องยิง /init ก่อน
},
{
"method": "POST",
"path": "/api/v3/process" // ขั้นตอนที่ 2: ต้องยิง /process ตามมาติดๆ
}
]
}
เปิดเว็บเบราว์เซอร์ไปที่: http://localhost:1080/mockserver/dashboard
========================================================================================
MOCKSERVER WEB DASHBOARD (PORT 1080)
========================================================================================
[ Active Expectations ] | [ Recorded Requests / Logs ] | [ Breakpoints ] | [ Reset All ]
----------------------------------------------------------------------------------------
Recorded Requests / Logs: - ทุกรายการ Request ที่วิ่งผ่าน Proxy จะมาปรากฏที่นี่
- สามารถคลิกดู Headers และ Body ของแต่ละ Request/Response ได้
"Create Expectation" Button: - ปุ่มลัดในแท็บ Logs ข้างๆ ทุก Request
- สกัดทราฟฟิกจริงไปสร้างเป็น Active Expectation ทันทีโดยไม่ต้องเขียน JSON เอง
Interactive Breakpoints: - ไปที่เมนู Breakpoints แล้วเปิดใช้งาน (Enable Breakpoint)
- กักทราฟฟิก In-flight ไว้ แล้วแก้ไข Payload สดๆ บนหน้าเว็บก่อนปล่อยผ่าน
mockserver-module3-enterprise/
├── docker-compose.yml
├── config/
│ ├── mockserver.properties
│ └── certs/
│ └── MockServerPKCS12.p12 # ใบรับรอง Root CA สำหรับทำ HTTPS Proxying
├── expectations/
│ ├── recorded/
│ │ └── bank-api-recorded.json # ไฟล์ Mocks ที่สกัดจาก Record/Replay
│ └── forwarding/
│ └── reverse-proxy-rules.json # Rules การทำ Port Forwarding
├── scripts/
│ ├── record_traffic.sh # สคริปต์สั่งยิงผ่าน Proxy แล้วสกัด Expectations
│ └── reset_mockserver.sh
└── tests/
└── ProxyAndVerificationTest.java
นั่งพิมพ์ JSON เองตามเอกสาร PDF เก่าที่ไม่ตรงกับระบบจริง:
{
"httpRequest": { "method": "POST", "path": "/payment" },
"httpResponse": { "body": "{\"status\": \"OK\"}" } // เซิร์ฟเวอร์จริงใช้ "SUCCESS" ไม่ใช่ "OK" -> พังบน Prod!
}
ยิงผ่าน Proxy 1 ครั้งแล้วสกัดสเปกจริงออกมา Replay ได้ตรง 100%:
curl -x http://localhost:1080 http://api.bank.com/payment -d '{"amount":100}'
curl -X PUT "http://localhost:1080/mockserver/retrieve?type=EXPECTATIONS" > expectations/recorded.json
ก่อนเริ่มทำ ตรวจสอบว่าเปิด MockServer ไว้ที่ http://localhost:1080 เรียบร้อยแล้ว
Setup & Action:
curl -v -x http://localhost:1080 "http://httpbin.org/get?userId=U999&role=admin"
Retrieve: curl -X PUT "http://localhost:1080/mockserver/retrieve?type=EXPECTATIONS" (ได้สเปก JSON Expectation ฉบับเต็มที่สกัดจาก Request/Response จริง)
Setup:
curl -X PUT "http://localhost:1080/mockserver/expectation" -H "Content-Type: application/json" -d '{"httpRequest": { "method": "GET", "path": "/get", "queryStringParameters": { "userId": ["U999"] } }, "httpResponse": { "statusCode": 200, "headers": { "Content-Type": ["application/json"] }, "body": "{\"source\": \"Replayed Mock\"}" }}'
Test: curl -i "http://localhost:1080/get?userId=U999" (ได้ HTTP 200 OK พร้อม Body {"source": "Replayed Mock"})
Action: ยิง Request 2 ครั้ง:
curl -X POST http://localhost:1080/api/v3/telemetry -d '{"event": "click_1"}'
curl -X POST http://localhost:1080/api/v3/telemetry -d '{"event": "click_2"}'
Verify: curl -X PUT "http://localhost:1080/mockserver/verify" -H "Content-Type: application/json" -d '{"httpRequest": { "method": "POST", "path": "/api/v3/telemetry" }, "times": { "exact": 2 }}' (ได้ HTTP 202 Accepted)
Action: ยิงตามลำดับ:
curl -X POST http://localhost:1080/api/v3/init curl -X POST http://localhost:1080/api/v3/process
Verify Sequence: curl -X PUT "http://localhost:1080/mockserver/verifySequence" -H "Content-Type: application/json" -d '{"httpRequests": [{"method": "POST", "path": "/api/v3/init"}, {"method": "POST", "path": "/api/v3/process"}]}' (ได้ HTTP 202 Accepted)
Setup:
curl -X PUT "http://localhost:1080/mockserver/expectation" -H "Content-Type: application/json" -d '{"httpRequest": { "method": "POST", "path": "/forward-test" }, "httpForward": { "host": "httpbin.org", "port": 80, "scheme": "HTTP" }}'
Test: curl -i -X POST http://localhost:1080/forward-test -d '{"data": "forwarded"}' (ได้รับ Response จาก httpbin.org)
Action:
curl -X PUT "http://localhost:1080/mockserver/reset"
Test Verification: curl -X PUT "http://localhost:1080/mockserver/retrieve?type=EXPECTATIONS" (ได้อาร์เรย์ว่างเปล่า [])
คลิกเลือกคำตอบข้อที่ถูกต้อง ระบบจะตรวจให้คะแนนและแสดงผลเฉลยพร้อมคำอธิบายทันที!
คะแนนของคุณคือ ...
เนื้อหาและแบบฝึกหัดทั้งหมดในวันนี้ ตอบและสะท้อนชื่อบท Day 3 / Module 3: Proxying, Record & Replay, and Interactive Breakpoints อย่างสมบูรณ์: การใช้ Proxying (Forward / HTTPS Tunneling) ช่วยให้เราเชื่อมต่อและบันทึกทราฟฟิกจริงจาก Third-party APIs ได้อย่างแม่นยำ, การใช้ Record & Replay Workflow ช่วยเปลี่ยนม้วนเทปบันทึกทราฟฟิกเป็น Mocks ที่เสถียรรวดเร็ว และการใช้ Interactive Breakpoints ก็ช่วยให้เราทดสอบดักแก้ไขข้อมูลสดกลางอากาศได้เหมือนมีกล้องตรวจจับและศุลกากรส่วนตัวนั่นเองครับ!