المحاكاة وحقن الأعطال
مراقبة الحركة تجيب عمّا يفعله التطبيق. وهذه الصفحة عن النصف الآخر: أن تجعل الشبكة تجيب بما لم تكن لتجيب به، لترى ماذا يفعل التطبيق حياله. خادم خلفي لم يُبنَ بعد، ونقطة نهاية تُرجع 500، واستجابة تستغرق ثماني ثوانٍ، وواجهة برمجية اختفت ببساطة.
كل ما هنا يعمل على كل منصّة يعمل عليها Chute، وكل ما يمسّ HTTPS يحتاج أولاً إلى تفعيل فك التشفير لذلك المضيف — فالطلب المشفَّر الذي لا يستطيع Chute قراءته لا يستطيع الإجابة عنه.
ما يستطيع Chute محاكاته وما لا يستطيع
يتدخّل Chute عند الاتصال وعند رسالة HTTP. وليس لديه مُشكّل حركة، ولذلك:
| يستطيع | إرجاع جسم جاهز، وإرجاع رمز حالة تختاره، وإضافة تأخير ثابت قبل طلب أو استجابة، ورفض الاتصال رفضاً قاطعاً، وإعادة عملاء HTTP/3 إلى TCP، وإرسال طلب إلى مضيف غير الذي طُلب |
| لا يستطيع | تحديد عرض النطاق، أو إسقاط الحزم أو إعادة ترتيبها، أو إضافة اضطراب، أو تدهور اتصال في منتصفه، أو محاكاة زمن ذهاب وإياب معيّن على مستوى النقل |
لا يوجد قسم [Throttle] في الإعدادات ولا حدّ سرعة في أي موضع. وإن كنت تحتاج وصلة بطيئة لا استجابة بطيئة، فذلك من شأن مُكيّف شبكة (Network Link Conditioner من Apple، أو موجّه)، لا من شأن Chute.
اختر آلية
| لمحاكاة | استخدم | أين |
|---|---|---|
| جسم استجابة غير موجود بعد | [Map Local] |
الاستجابة الوهمية |
| 503 بالضبط | [URL Rewrite] … reject |
إعادة كتابة الرابط |
| 200 فارغ، أو صورة فارغة، أو كائن JSON فارغ | reject-200 وreject-img وreject-dict |
إعادة كتابة الرابط |
| أي حالة أخرى — 401 و429 و500 | سكربت http-request |
برمجة JavaScript |
| زمن استجابة | سكربت http-request أو http-response |
برمجة JavaScript |
| نقطة نهاية غير قابلة للوصول ببساطة | قاعدة REJECT |
السياسة المدمجة |
| عميل لا يتراجع إلى TCP | block-quic |
خيارات متنوعة |
| خادم خلفي مختلف خلف الرابط نفسه | [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="
ثلاثة أمور تحدّد نجاح ذلك:
- يجب أن يطابق التعبير النمطي الرابط كاملاً، لا جزءاً منه. أنهِ النمط بـ
.*إلا إذا كنت تقصد رابطاً بلا سلسلة استعلام إطلاقاً. - يقرأ
data=الجهازُ الذي يشغّل Chute. وعلى Mac هذا مريح — عدّل الملف فيرى الطلب التالي التغيير. أما على الهاتف أو Apple TV فمسار من جهاز Mac لديك لا يعني شيئاً؛ استخدم هناكbase64=، أو قدّم الملف عبر HTTP واستعمل إعادة كتابة الرابط. - الحالة دائماً
200 OK. ليس لدى[Map Local]أي وسيلة لتعيينها، والاتصال يُغلق بعد الإجابة. ولأي حالة أخرى استخدم سكربتاً — انظر أدناه.
ويدعم الجسم متغيّرات القوالب {{ "{{url}}" }} و{{ "{{host}}" }} و{{ "{{path}}" }} و{{ "{{method}}" }} و{{ "{{ua}}" }}، وهذا يكفي لصنع محاكاة تردّ ما سُئلت عنه.
رمز حالة خطأ
لأجل 503 لا حاجة إلى سكربت — فإعادة كتابة رابط بوضع 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 السكربت في أي موضع من الرابط، بخلاف عائلات إعادة الكتابة — فبادئة مثل ^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 — إعادة الاستجابة الحقيقية متأخرة ثماني ثوانٍ
setTimeout(function () {
$done({})
}, 8)
والميزانية هي timeout السكربت نفسه: خمس ثوانٍ افتراضياً، وأي قيمة فوق 30 تُقصّ إلى 30. والسكربت الذي لم يستدعِ $done() عند انتهاء المهلة يُعامَل على أنه تمرير — فتمضي الرسالة بلا تعديل — ولذلك فالتأخير الأطول من المهلة لا يفشل فشلاً صاخباً، بل يكفّ عن التأخير فحسب. اضبط 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 بعنوان تختاره أنت — جهاز تجريبي، أو عنوان لا يؤدي إلى شيء إن كنت تريد اتصالاً تنتهي مهلته بدل اتصال مرفوض. وهو يسري على كل البروتوكولات ولا يحتاج فك تشفير. وامسح ذاكرة DNS بعد تغييره.
[URL Rewrite]
^https://api\.example\.com/v1/(.*) https://staging.example.com/v1/$1 header
يعيد وضع header كتابة الطلب في مكانه ويصلح ترويسة Host معه، فلا يعلم العميل أنه أُعيد توجيهه. وهذه في طبقة HTTP فتحتاج فك التشفير مع HTTPS. وحين يتعذّر إعادة كتابة الوجهة في مكانها يتراجع Chute إلى الإجابة برمز 307 نحو الرابط الجديد.
التأكد من أنها عملت
القاعدة التي لا تطابق قط تبدو تماماً كقاعدة طابقت ولم تفعل شيئاً — وهكذا تفشل هذه الصفحة بأكملها.
- إعادات الكتابة والمحاكاة: تسرد صفحة Rules في وحدة تحكم الويب كل قاعدة URL Rewrite و Header Rewrite و Body Rewrite و Map Local عملت في هذا التشغيل، مع عدّادها. وغيابها عن القائمة يعني أنها لم تطابق قط. والبيانات نفسها في
rewrite_hitsضمنGET /api/rules. - لكل اتصال: افتح الاتصال في وحدة التحكم أو في Dashboard واقرأ صفوف إعادات الكتابة المطبَّقة، فهي تسمّي القاعدة بكلماتها هي.
- السكربتات لا تظهر في ذلك الجدول. دليل السكربت هو مخرجاته: تصل أسطر
console.logإلى السجل، وتُقرأ في صفحة Logs بوحدة التحكم أو عبرGET /api/logs.
التنظيف بعد الانتهاء
القواعد المضافة من وحدة التحكم أو من Dashboard أو عبر POST /api/rewrites/:family تعيش في النواة العاملة وتزول عند إعادة التشغيل التالية — وهذا مثالي لتجربة وسيّئ جداً لشيء تعتمد عليه. أما قواعد ملف الإعدادات فتنجو من إعادة التشغيل، وهذا يجعله مكاناً جيداً لمحاكاة، وشيئاً لا ينبغي نسيانه أبداً: سطر [Map Local] مترك في الإعدادات سيظل يجيب عن الطلبات بعد أسابيع، وهو يبدو تماماً كخادم معطّل.
هذه الصفحة ترجمة للنسخة الإنجليزية. في حال وجود اختلاف، يُعتمد على النسخة الإنجليزية.
ملاحظة: التطبيق لا يدعم اللغة العربية حاليًا.