การจำลองและการแทรกความผิดพลาด

การเฝ้าดูทราฟฟิกตอบว่าแอปทำอะไร หน้านี้ว่าด้วยอีกครึ่งหนึ่ง: ทำให้เครือข่ายตอบสิ่งที่ปกติมันจะไม่ตอบ เพื่อดูว่าแอปจะจัดการอย่างไร แบ็กเอนด์ที่ยังไม่ได้สร้าง เอนด์พอยต์ที่คืน 500 การตอบกลับที่ใช้เวลาแปดวินาที API ที่หายไปเฉย ๆ

ทุกอย่างในหน้านี้ทำงานบนทุกแพลตฟอร์มที่ Chute รันได้ และทุกอย่างที่แตะ HTTPS ต้องเปิดการถอดรหัสสำหรับโฮสต์นั้นก่อน — คำขอที่เข้ารหัสซึ่ง Chute อ่านไม่ได้ ก็เป็นคำขอที่ Chute ตอบแทนไม่ได้

Chute จำลองอะไรได้และไม่ได้

Chute แทรกแซงที่การเชื่อมต่อและที่ข้อความ HTTP มันไม่มีตัวจัดรูปทราฟฟิก ดังนั้น:

ทำได้ คืนเนื้อหาสำเร็จรูป คืนรหัสสถานะที่เลือก ใส่ความหน่วงคงที่ก่อนคำขอหรือการตอบกลับ ปฏิเสธการเชื่อมต่อไปเลย บังคับไคลเอนต์ HTTP/3 ให้กลับไปใช้ TCP ส่งคำขอไปยังโฮสต์อื่นที่ไม่ใช่โฮสต์ที่ขอ
ทำไม่ได้ จำกัดแบนด์วิดท์ ทิ้งหรือสลับลำดับแพ็กเก็ต เพิ่มจิตเตอร์ ทำให้การเชื่อมต่อแย่ลงกลางคัน หรือจำลอง RTT ที่เจาะจงในระดับชั้นขนส่ง

ไม่มีส่วน [Throttle] ในการกำหนดค่า และไม่มีการจำกัดความเร็วที่ไหนเลย ถ้าคุณต้องการลิงก์ที่ช้าแทนที่จะเป็นการตอบกลับที่ช้า นั่นเป็นเรื่องของตัวจำลองสภาพเครือข่าย (Network Link Conditioner ของ Apple หรือเราเตอร์) ไม่ใช่ของ Chute

เลือกกลไก

สิ่งที่จะจำลอง ใช้ ที่ไหน
เนื้อหาการตอบกลับที่ยังไม่มีอยู่จริง [Map Local] การตอบกลับจำลอง
503 พอดี [URL Rewrite]reject URL Rewrite
200 ที่ว่างเปล่า รูปเปล่า อ็อบเจ็กต์ JSON ว่าง reject-200, reject-img, reject-dict URL Rewrite
รหัสสถานะอื่น ๆ — 401, 429, 500 สคริปต์ http-request การเขียนสคริปต์ JS
ความหน่วง สคริปต์ http-request หรือ http-response การเขียนสคริปต์ JS
เอนด์พอยต์ที่เข้าไม่ถึงเลย กฎ REJECT นโยบายในตัว
ไคลเอนต์ที่ไม่ยอมถอยไปใช้ TCP block-quic ตัวเลือกเบ็ดเตล็ด
แบ็กเอนด์อื่นหลัง URL เดิม [Host] หรือโหมด header ของ [URL Rewrite] การแมป DNS ในเครื่อง

เนื้อหาการตอบกลับสำเร็จรูป

[Map Local] ตอบคำขอที่ตรงจากไฟล์หรือจาก base64 ที่ฝังไว้ โดยไม่ถามเซิร์ฟเวอร์จริง:

[Map Local]
^https://api\.example\.com/v1/profile.* data="/Users/me/mocks/profile.json"
^https://api\.example\.com/v1/flags.* base64="eyJiZXRhIjogdHJ1ZX0="

สามสิ่งที่ตัดสินว่ามันจะได้ผลหรือไม่:

  • นิพจน์ทั่วไปต้องตรงทั้ง URL ไม่ใช่บางส่วน ให้จบรูปแบบด้วย .* เว้นแต่คุณตั้งใจจะตรงกับ URL ที่ไม่มีสตริงคิวรีเลย
  • data= ถูกอ่านโดยอุปกรณ์ที่รัน Chute บน Mac นั่นสะดวก — แก้ไฟล์แล้วคำขอถัดไปก็เห็นการเปลี่ยนแปลง บนโทรศัพท์หรือ Apple TV พาธจาก Mac ของคุณไม่มีความหมาย ให้ใช้ base64= แทน หรือเสิร์ฟไฟล์ผ่าน HTTP แล้วใช้ URL Rewrite
  • สถานะเป็น 200 OK เสมอ [Map Local] ไม่มีทางกำหนดสถานะได้ และการเชื่อมต่อจะถูกปิดหลังตอบ สำหรับสถานะอื่นให้ใช้สคริปต์ — ดูด้านล่าง

เนื้อหารองรับตัวแปรเทมเพลต {{ "{{url}}" }}, {{ "{{host}}" }}, {{ "{{path}}" }}, {{ "{{method}}" }} และ {{ "{{ua}}" }} ซึ่งเพียงพอสำหรับทำการจำลองที่สะท้อนกลับว่าถูกถามอะไรมา

รหัสสถานะข้อผิดพลาด

สำหรับ 503 ไม่ต้องใช้สคริปต์ — URL rewrite โหมด reject คืน HTTP/1.1 503:

[URL Rewrite]
^https://api\.example\.com/v1/orders.* _ reject

โหมดพี่น้องครอบคลุมรูปแบบอื่นของ "ไม่มีอะไรใช้ได้": reject-200 (200 พร้อมเนื้อหาว่าง), reject-img (GIF ขนาด 1×1), reject-dict ({} แบบ JSON, 200) ทั้งหมดมีผลกับ HTTPS เฉพาะเมื่อโฮสต์นั้นกำลังถูกถอดรหัสอยู่

สำหรับ รหัสสถานะอื่นใดก็ตาม สคริปต์ http-request จะลัดวงจรคำขอ:

[Script]
Fail429 = type=http-request, script-path=/Users/me/mocks/fail429.js, pattern=^https://api\.example\.com/v1/orders
// fail429.js — ตอบโดยไม่ติดต่อเซิร์ฟเวอร์
$done({
    response: {
        status: 429,
        headers: {
            "Content-Type": "application/json",
            "Retry-After": "30"
        },
        body: JSON.stringify({ error: "rate_limited" })
    }
})

pattern ของสคริปต์ตรงที่ตำแหน่งใดก็ได้ใน URL ต่างจากตระกูลการเขียนใหม่ — คำนำหน้าอย่าง ^https://api\.example\.com/v1/orders ก็พอแล้ว ไม่ต้องเติม .* ท้าย

ในเส้นทาง HTTP/1.1 บรรทัดสถานะถูกเขียนด้วยวลีเหตุผล OK เสมอไม่ว่ารหัสจะเป็นอะไร (HTTP/1.1 429 OK) ไคลเอนต์อ่านตัวเลขไม่ใช่วลี จึงเป็นเรื่องผิวเผิน — แต่คุณจะเห็นแบบนั้นในข้อมูลดิบที่จับได้

ความหน่วง

สคริปต์จะกั้นข้อความไว้จนกว่าจะเรียก $done() ตัวจับเวลาจึงคือความหน่วง:

[Script]
SlowAPI = type=http-response, script-path=/Users/me/mocks/slow.js, pattern=^https://api\.example\.com/v1/, timeout=15
// slow.js — ส่งการตอบกลับจริงคืนช้าไป 8 วินาที
setTimeout(function () {
    $done({})
}, 8)

งบประมาณคือ timeout ของสคริปต์เอง: ค่าเริ่มต้น 5 วินาที และค่าที่เกิน 30 จะถูกตัดเหลือ 30 สคริปต์ที่ยังไม่เรียก $done() เมื่อหมดเวลาจะถูกถือเป็นการปล่อยผ่าน — ข้อความเดินหน้าต่อโดยไม่ถูกแก้ — ความหน่วงที่ยาวกว่า timeout จึงไม่ได้ล้มเหลวอย่างเอิกเกริก มันแค่เลิกหน่วงเท่านั้น ตั้ง timeout ให้มากกว่าความหน่วงที่ต้องการ ดังตัวอย่างข้างบน

ใช้ type=http-request เพื่อหน่วงก่อนติดต่อเซิร์ฟเวอร์ (แอปเห็นการไป-กลับที่ช้า) และ type=http-response เพื่อหน่วงหลังจากนั้น (เซิร์ฟเวอร์เร็ว แต่แอปก็ยังต้องรอ)

เอนด์พอยต์ที่หายไปเฉย ๆ

การจำลองแทนที่การตอบกลับ ส่วนกฎ REJECT ปฏิเสธการเชื่อมต่อ มันทำงานที่ระดับการเชื่อมต่อ จึงครอบคลุมทุกโปรโตคอลไม่ใช่แค่ HTTP และไม่ต้องถอดรหัส:

[Rule]
DOMAIN-SUFFIX,api.example.com,REJECT

REJECT-DROP, REJECT-TINYGIF และ REJECT-NO-DROP ถูกยอมรับเพื่อความเข้ากันได้ และทั้งหมดทำงานเหมือน REJECT ธรรมดา สำหรับคำขอ HTTP นั้น show-error-page-for-reject = true จะแทนการปฏิเสธเปล่า ๆ ด้วยหน้าข้อผิดพลาดที่อ่านได้ ทำให้เห็นชัดในเบราว์เซอร์ว่าการบล็อกนั้นเป็นของคุณ

นี่ยังเป็นวิธีตรวจว่ามีเส้นทางสำรองอยู่จริงหรือไม่ — ปฏิเสธโฮสต์หลักแล้วดูว่าแอปเอื้อมไปหาโฮสต์รองหรือแค่หมุนอยู่กับที่

บังคับไคลเอนต์ให้ลงจาก HTTP/3

QUIC วิ่งบน UDP และ Chute ถอดรหัสมันไม่ได้ แอปที่ใช้ HTTP/3 จึงมองไม่เห็นด้วยกลไกใด ๆ ในหน้านี้ การปฏิเสธโฟลว์ QUIC ของมันทำให้ไคลเอนต์ที่รองรับลองใหม่ผ่าน TCP ซึ่งทุกอย่างทำงานได้:

[General]
block-quic = on

auto ปฏิเสธ QUIC เฉพาะเมื่อโฟลว์มุ่งไปยังพร็อกซี ส่วน on ปฏิเสธทุกที่รวมถึง DIRECT สำหรับทราฟฟิกที่เข้ามาทาง TUN นั้น Chute ตอบโฟลว์ QUIC ที่ถูกปฏิเสธด้วย ICMP Port Unreachable ไคลเอนต์จึงถอยกลับทันทีแทนที่จะรอจนหมดเวลา

ส่งคำขอไปที่อื่น

สองวิธีในสองชั้น:

[Host]
api.example.com = 10.0.0.5

การแมป [Host] ตอบการค้นหา DNS ด้วยที่อยู่ที่คุณเลือก — เครื่อง staging หรือที่อยู่ที่ไม่ไปไหนเลย ถ้าสิ่งที่คุณต้องการคือการเชื่อมต่อที่หมดเวลาแทนที่จะถูกปฏิเสธ มันมีผลกับทุกโปรโตคอลและไม่ต้องถอดรหัส ล้างแคช DNS หลังเปลี่ยน

[URL Rewrite]
^https://api\.example\.com/v1/(.*) https://staging.example.com/v1/$1 header

โหมด header เขียนคำขอใหม่ในที่และแก้เฮดเดอร์ Host ให้ด้วย ไคลเอนต์จึงไม่รู้เลยว่าถูกเปลี่ยนทาง วิธีนี้อยู่ระดับ HTTP จึงต้องถอดรหัสสำหรับ HTTPS เมื่อปลายทางเขียนใหม่ในที่ไม่ได้ Chute จะถอยไปตอบด้วย 307 ชี้ไป URL ใหม่แทน

ยืนยันว่ามันทำงานจริง

กฎที่ไม่เคยตรงเลยหน้าตาเหมือนกฎที่ตรงแล้วไม่ทำอะไรทุกประการ — นั่นคือวิธีที่ทั้งหน้านี้ล้มเหลว

  • การเขียนใหม่และการจำลอง: หน้า กฎ ของคอนโซลเว็บแสดงรายการกฎ URL Rewrite, Header Rewrite, Body Rewrite และ Map Local ทุกข้อที่ทำงานในรอบนี้พร้อมจำนวนครั้ง ถ้าไม่อยู่ในรายการแปลว่ามันไม่เคยตรงเลย ข้อมูลชุดเดียวกันอยู่ใน rewrite_hits ของ GET /api/rules
  • รายการเชื่อมต่อ: เปิดการเชื่อมต่อนั้นในคอนโซลหรือ Dashboard แล้วอ่านแถว การเขียนใหม่ที่ใช้ ซึ่งเรียกชื่อกฎด้วยถ้อยคำของกฎเอง
  • สคริปต์ไม่ปรากฏในตารางนั้น หลักฐานของสคริปต์คือผลลัพธ์ของตัวมันเอง บรรทัด console.log จะลงในบันทึก อ่านได้ที่หน้า บันทึก ของคอนโซลหรือด้วย GET /api/logs

เก็บกวาด

กฎที่เพิ่มจากคอนโซล จาก Dashboard หรือผ่าน POST /api/rewrites/:family อยู่ในเคอร์เนลที่กำลังทำงาน และหายไปเมื่อรีสตาร์ตครั้งถัดไป ซึ่งเหมาะกับการทดลอง แต่เป็นที่แย่มากสำหรับเก็บสิ่งที่คุณต้องพึ่งพา กฎในไฟล์การกำหนดค่าอยู่รอดข้ามการรีสตาร์ต จึงเป็นที่ดีสำหรับเก็บการจำลอง และเป็นสิ่งที่ไม่ควรลืมอย่างยิ่ง: บรรทัด [Map Local] ที่ทิ้งไว้ในการกำหนดค่ายังคงตอบคำขออยู่อีกหลายสัปดาห์ถัดมา และหน้าตาเหมือนเซิร์ฟเวอร์ที่พังทุกประการ

S. Smart Rabbit LLC © All Rights Reserved            updated 2026-09-05 00:57:27

หน้านี้เป็นฉบับแปลจากเวอร์ชันภาษาอังกฤษ หากเนื้อหาไม่ตรงกัน ให้ยึดเวอร์ชันภาษาอังกฤษเป็นหลัก

results matching ""

    No results matching ""