ה-API עונה ב-Safari באותו טלפון, ואילו הבקשה של האפליקציה מגיעה לפסק זמן. הפער הזה הוא בדרך כלל לא המנהרה: אפליקציה שקוראת לשירות פנימי שולחת בקשת HTTPS רגילה, וה-VPN שכבר קיים במכשיר רק קובע אם יש לבקשה הזו נתיב. כתיבת מנהרה שנייה לתוך האפליקציה היא החלטת מוצר, לא תיקון לפסק זמן. מה שלהלן מסווג את הכשל לפי המקום שבו הוא מתרחש, תוך שימוש במשטח השגיאות שכבר יש לאפליקציה.

התחילו מהשגיאה, לא מהמנהרה

URLSession מדווח על כשלי תעבורה כערכי NSError בתוך NSURLErrorDomain, והקוד הוא הראיה הזולה ביותר שיש. לפני שמשנים תצורה כלשהי, תעדו את הקוד הזה יחד עם שם המארח שנכשל וזמן המשימה שחלף. פסק זמן, כשל שם וכשל אמון נראים זהים על המסך ודורשים שלושה תיקונים שונים. סווגו קודם, ואז קראו את הקטע של אותה מחלקה.

מדדי המשימה עונים על השאלה הבאה, אם בכלל נוצר חיבור, מה שמפריד בין בקשה שמעולם לא היה לה נתיב לבין בקשה שהשרת התעכב יותר מדי במענה עליה. שום דבר מזה לא דורש שינוי במנהרה; הוא דורש שהאבחון של הבקשה עצמה יודפס במקום שתוכלו לקרוא.

פתרון השמות נכשל לפני כל דבר אחר

שם משרד קצר כמו api.corp.example תלוי בדרך כלל בתחום חיפוש שהטלפון לא נושא, ולכן האפליקציה מפענחת שם שקיים רק בתוך הבניין. NSURLErrorCannotFindHost הוא החתימה. שם המארח המלא חייב להיפתר דרך כל פותר שה-VPN מתקין, והאפליקציה צריכה לבקש את הצורה המלאה בכל פעם שתחום החיפוש אינו מובטח. החלפת השם בכתובת וכיבוי בדיקות התעודה מעבירים את הכשל במקום לתקן אותו.

רשומת DNS פרטית ותעודה שהונפקה בדיוק לשם הזה הם הזוג הנתמך. כל השאר הוא עקיפה שמגיעה למשתמשים.

פסק זמן הוא שאלה של נתיב, לא של שם

NSURLErrorTimedOut פירושו שהשם נפתר ושום דבר לא ענה, מה שמצביע על הנתיב, מדיניות החבילות או השירות. כשהמנהרה מוקצית לכל אפליקציה, אפליקציה אחרת שמגיעה לאותו שרת לא אומרת דבר על הבנייה שלכם, כי המיפוי הזה אינו משותף. בדקו שהחבילה שאתם מריצים נמצאת בתוך ההקצאה, ואז בדקו שנתיב השירות מותר עבורה. בניית פיתוח שהותקנה מחוץ להקצאה יכולה לשבת לגמרי מחוץ למנהרה ולהיראות כמו API שבור.

השוואה בדפדפן מראה שלאיזושהי אפליקציה במכשיר יש נתיב. היא לעולם לא מוכיחה שלבנייה שלכם יש כזה, ולכן שתי הבדיקות חייבות להיערך בנפרד.

כשלי אמון עוסקים בשם שעל התעודה

NSURLErrorServerCertificateUntrusted יחד עם שגיאת ה-TLS שמתחתיה פירושו שהשרשרת או בדיקת הזהות נכשלו. CA פנימי חייב להיות מהימן במכשיר, ותעודה שהונפקה לשם מארח אחר נשארת שגויה אחרי כל תצורה מחדש של הרשת. ההנחיות של App Transport Security ממשיכות לחול על החיבורים האלה שטוענים URL, ומנהרה סביב שירות HTTP פשוט לא הופכת את השירות הזה למאובטח מקצה לקצה.

תקנו את הזהות או את עוגן האמון והשאירו את רשימת החריגים ריקה. חריגה גורפת לטעינה שרירותית מסתירה את הכשל בזמן הפיתוח ומשאירה אותו במקום לכל משתמש לאחר מכן.

דחיית HTTP שייכת לאפליקציה, לא לרשת

401 או 403 לאחר לחיצת יד שהושלמה פירושם שהבקשה הגיעה והשירות דחה אותה, כך שהשאלה שנותרה היא חשבון, קהל יעד של אסימון, היקף או מפתח. תעדו את קוד המצב ואת שם המארח, ולעולם לא את אסימון הנושא או גוף התגובה. בשלב הזה המנהרה עושה את שלה, ושינויי רשת נוספים רק מעכבים את התיקון האמיתי.

הטבלה היא הסיווג שכדאי להחזיק ליד הטרמינל: שורה אחת לכל כשל שהאפליקציה באמת יכולה לדווח עליו. הדפיסו את הקוד לפני שאתם קוראים אותו, כי השורה שתבחרו מחליטה איזה קטע תעבדו דרכו.

Where it failsWhat the app seesFirst check
name resolutionNSURLErrorCannotFindHost (-1003)resolve the fully qualified name from the device itself
no path, or no answerNSURLErrorTimedOut (-1001)is this bundle inside the per-app mapping, and is the service path allowed
TLS trustNSURLErrorServerCertificateUntrusted (-1202)does the certificate name match the host, and is the internal CA trusted
service refusalHTTP 401 or 403 after a completed handshakeaccount, token audience, scope or key

כל שורה זולה יותר לבדיקה מזו שמתחתיה, וכל אחת פוסלת שכבה אחרת של אותה בקשה. רדו בטבלה עד ששורה מתאימה, ואז הפסיקו לשנות את הרשת.

מאמרים קשורים