העברה ל-User-Agent Client Hints

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

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

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

איסוף נתוני סוכן משתמש ושימוש בהם

כמו בכל צורה של איסוף נתונים, תמיד צריך להבין למה אוספים אותו. השלב הראשון, גם אם לא כדי להבין איפה ולמה אתם משתמשים בנתוני סוכן משתמש (user-agent).

אם לא ידוע לך אם נעשה שימוש בנתונים של סוכן משתמש או איפה, כדאי לבצע חיפוש את הקוד של ממשק הקצה לשימוש ב-navigator.userAgent והקוד העורפי לשימוש שימוש בכותרת ה-HTTP User-Agent. צריך לבדוק גם את הקוד בממשק הקצה לשימוש בתכונות שכבר הוצאו משימוש, כמו navigator.platform navigator.appVersion.

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

  • השם או הגרסה של הדפדפן
  • השם או הגרסה של מערכת ההפעלה
  • היצרן או הדגם של המכשיר
  • סוג המעבד (CPU), הארכיטקטורה או הביטים (לדוגמה, 64 ביט)

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

האם אתם משתמשים רק בנתונים בסיסיים של סוכן משתמש?

קבוצת ברירת המחדל של רמזים על הלקוח בסוכן המשתמש כוללת:

  • Sec-CH-UA: שם הדפדפן וגרסה ראשית/משמעותית
  • Sec-CH-UA-Mobile: ערך בוליאני שמציין מכשיר נייד
  • Sec-CH-UA-Platform: שם מערכת ההפעלה
    • לתשומת לבך, המידע הזה עודכן במפרט והוא יבוא לידי ביטוי Chrome ודפדפנים נוספים שמבוססים על Chromium בקרוב.

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

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

אפשר וכדאי לעבור ל-User-Agent Client Hints, אבל יכול להיות שיש לכם אילוצים בקוד או במשאבים שמונעים זאת. צמצום המידע מחרוזת ה-user-agent באופן הזה, שתואמת לאחור, נועדה להבטיח שלמרות שקוד קיים יקבל מידע פחות מפורט, הוא עדיין אמור לשמר פונקציונליות בסיסית.

אסטרטגיה: JavaScript API על פי דרישה בצד הלקוח

אם משתמשים כרגע ב-navigator.userAgent, צריך לעבור אל העדפה של navigator.userAgentData לפני שחוזרים לניתוח user-agent.

if (navigator.userAgentData) {
  // use new hints
} else {
  // fall back to user-agent string parsing
}

אם אתם בודקים את הגרסה לנייד או למחשב, צריך להשתמש בערך הבוליאני mobile:

const isMobile = navigator.userAgentData.mobile;

userAgentData.brands הוא מערך אובייקטים עם brand ו-version נכסים שבהם הדפדפן יכול לציין את התאימות שלו המותגים. אפשר לגשת אליהם ישירות כמערך, או להשתמש קריאה ל-some() כדי לבדוק אם קיימת רשומה ספציפית:

function isCompatible(item) {
  // In real life you most likely have more complex rules here
  return ['Chromium', 'Google Chrome', 'NewBrowser'].includes(item.brand);
}
if (navigator.userAgentData.brands.some(isCompatible)) {
  // browser reports as compatible
}

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

navigator.userAgentData.getHighEntropyValues(['model'])
  .then(ua => {
    // requested hints available as attributes
    const model = ua.model
  });

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

אסטרטגיה: כותרת סטטית בצד השרת

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

כדאי להשתמש באסטרטגיה הזו אם אתם משנים או מתאימים אישית את התשובות מוצגת על סמך נתוני סוכן המשתמש.

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

לדוגמה, ברירות המחדל הנוכחיות עבור Chrome מיוצגות כך:

❌️ כותרות של תשובות

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA

אם הייתם רוצים גם לקבל את דגם המכשיר בתשובות, שליחה:

❌️ כותרות של תשובות

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Platform, Sec-CH-UA

במהלך העיבוד בצד השרת, עליך לבדוק קודם אם הכותרת Sec-CH-UA נשלחה ולאחר מכן חזרה לכותרת User-Agent בניתוח, אם הוא לא זמין.

אסטרטגיה: האצלת רמזים לבקשות ממקורות שונים

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

לדוגמה, נניח שב-https://blog.site מתארחות משאבים באמצעות https://cdn.site, תוכלו להחזיר משאבים שעברו אופטימיזציה למכשיר ספציפי. האפליקציה https://blog.site יכולה לבקש את הרמז לSec-CH-UA-Model, אבל היא צריכה להאציל אותו באופן מפורש ל-https://cdn.site באמצעות Permissions-Policy הכותרת. רשימת הרמזים בשליטת המדיניות זמינה בטיפים של לקוחות תשתית טיוטה

🎶️ תשובה שהתקבלה מ-blog.site בקשר להענקת הרמז

Accept-CH: Sec-CH-UA-Model
Permissions-Policy: ch-ua-model=(self "https://cdn.site")

⬆️ בקשה למשאבי משנה ב-cdn.site כוללת את הרמז שהוקצה

Sec-CH-UA-Model: "Pixel 5"

אפשר לציין כמה רמזים לכמה מקורות, ולא רק מהטווח של ch-ua:

❌️ תשובה שהתקבלה על ידי blog.site מהאצלת רמזים לכמה מקורות

Accept-CH: Sec-CH-UA-Model, DPR
Permissions-Policy: ch-ua-model=(self "https://cdn.site"),
                    ch-dpr=(self "https://cdn.site" "https://img.site")

אסטרטגיה: האצלת רמזים למסגרות iframe

iframes ממקורות שונים פועלים באופן דומה למשאבים ממקורות שונים, אבל לציין את הרמזים שרוצים להעניק להם גישה במאפיין allow.

🪁️ תגובה של blog.site

Accept-CH: Sec-CH-UA-Model

↪️ HTML של blog.site

<iframe src="https://widget.site" allow="ch-ua-model"></iframe>

⬆️ בקשה אל widget.site

Sec-CH-UA-Model: "Pixel 5"

המאפיין allow ב-iframe יחליף כל כותרת Accept-CH אשר ייתכן ש-widget.site ישלח את עצמו, לכן חשוב לוודא שציינת את כל לאתר ב-iframe.

אסטרטגיה: רמזים דינמיים בצד השרת

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

מה שחשוב לזכור הוא שכל מופע של Accept-CH הכותרת תחליף בפועל את הקבוצה הקיימת. אז אם אתם מנהלים הגדרת הכותרת, אז כל דף חייב לבקש את קבוצת הרמזים המלאה הנדרשת.

לדוגמה, ייתכן שיש קטע באתר שבו תרצו לספק סמלים ופקדים התואמים למערכת ההפעלה של המשתמש. בשביל זה אפשר אני גם רוצה למשוך בנוסף Sec-CH-UA-Platform-Version כדי להציג במשאבי משנה.

🎶️ כותרות תגובה של /blog

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA

🎶️ כותרות תגובה של /app

Accept-CH: Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA-Platform-Version, Sec-CH-UA

אסטרטגיה: נדרשים רמזים בצד השרת בבקשה הראשונה

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

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

לרמזים נוספים לגבי הבקשה הראשונה, יש שתי אפשרויות. קודם כל, אפשר צריך להשתמש בכותרת Critical-CH. זה אותו פורמט כמו Accept-CH אבל היא מנחה את הדפדפן שעליו לנסות מחדש את הבקשה באופן מיידי אם נשלח בלי הרמז הקריטי.

⬆️ בקשה ראשונית

[With default headers]

❌️ כותרות של תשובות

Accept-CH: Sec-CH-UA-Model
Critical-CH: Sec-CH-UA-Model

🔃 הדפדפן מנסה שוב את הבקשה הראשונית עם הכותרת הנוספת

[With default headers + …]
Sec-CH-UA-Model: Pixel 5

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

במצבים שבהם אתם באמת דורשים רמזים נוספים של טעינת הדף הראשון, המהימנות של רמזים ללקוח (Client Hints Reliability) הצעה פריסת מסלול כדי לציין רמזים בהגדרות ברמת החיבור. הזה עושה שימוש ב-Application-Layer Protocol תוסף הגדרות(ALPS) ל-TLS 1.3 כדי לאפשר את ההעברה המוקדמת של הרמזים בחיבורי HTTP/2 ו-HTTP/3. הזה עדיין בשלב מוקדם מאוד, אבל אם אתם מנהלים באופן פעיל TLS משלכם הגדרות החיבור לאינטרנט. אז זו הזדמנות אידיאלית לתרום.

אסטרטגיה: תמיכה מדור קודם

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

מילוי מחדש של UA-CH הוא סוג קטן שמאפשרת להחליף את navigator.userAgent במחרוזת חדשה נוצר מערכי ה-navigator.userAgentData המבוקשים.

לדוגמה, הקוד הזה יפיק מחרוזת סוכן משתמש שבנוסף כולל את ה'מודל' רמז:

import { overrideUserAgentUsingClientHints } from './uach-retrofill.js';
overrideUserAgentUsingClientHints(['model'])
  .then(() => { console.log(navigator.userAgent); });

המחרוזת שמתקבלת תציג את המודל Pixel 5, אבל עדיין מציגה את הערך המצומצם יותר 92.0.0.0 כי לא נשלחה בקשה לרמז uaFullVersion:

Mozilla/5.0 (Linux; Android 10.0; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.0.0 Mobile Safari/537.36

תמיכה נוספת

אם האסטרטגיות האלה לא יכסו את התרחיש לדוגמה שלכם, תוכלו להתחיל דיון ב: privacy-sandbox-dev-support מאגר כדי שנוכל לבדוק את הבעיה ביחד.

צילום: ריקרדו רוצ'ה ב-Un שמוצגת