Lompat ke konten
dokumentasi.id
Commit bd74801
v2
Star10 rb

6

Deteksi Client Hints

Selain UA string, ua-parser-js membaca sumber data kedua: client hints. Halaman Pipeline Deteksi Regex dan String Map menjelaskan pembacaan UA string; di sini dijelaskan bagaimana header sec-ch-ua* dipetakan ke field hasil yang sama lewat UACHData dan parseCH(), serta bagaimana hasilnya jatuh kembali ke UA string ketika hints tidak tersedia.

Dua jalur masuk data hints

UAParser menerima headers sebagai argumen pertama. Konstruktor memeriksa argumen bertipe object dan memperlakukannya sebagai headers, lalu menormalkan nama setiap header menjadi huruf kecil; objek Headers yang memiliki method append diubah lebih dulu menjadi objek biasa, dan nilai berupa array digabung dengan ', '. src/main/ua-parser.js:1422-1438 src/main/ua-parser.js:1440-1456

Setelah normalisasi, satu instance UACHData dibuat dengan isHttpUACH = true dan dibagikan ke setiap UAItem sebagai uaCH saat getter membuat item. src/main/ua-parser.js:1463-1469 src/main/ua-parser.js:1471-1490

withClientHints() memilih satu dari dua cabang pemrosesan berdasarkan NAVIGATOR_UADATA, yaitu window.navigator.userAgentData yang dibaca sekali saat modul dimuat. src/main/ua-parser.js:1128-1146

LingkunganKondisiJalur yang dijalankanNilai balik
server / Node, atau browser tanpa userAgentData!NAVIGATOR_UADATAitem.parseCH().get()IData, sinkron
Chromium 85+NAVIGATOR_UADATA tersediagetHighEntropyValues(CH_ALL_VALUES) lalu setCH(new UACHData(res, false)), parseCH(), get()Promise berisi IData

src/main/ua-parser.js:1128-1146

Karena IData.prototype.then didefinisikan, kedua bentuk itu dapat dipakai dengan pola .then() yang sama, sehingga UAParser(headers).withClientHints().then(ua => ...) bekerja di server maupun di browser. src/main/ua-parser.js:1177-1195 test/unit/ua-ch.js:109-125

Method ini juga tersedia pada hasil setiap getter, misalnya new UAParser(headers).getBrowser().withClientHints() atau .getDevice().withClientHints(). test/unit/ua-ch.js:20-25

sequenceDiagram
    participant C as Caller
    participant P as UAParser
    participant D as UACHData
    participant I as IData
    C->>P: new UAParser(headers)
    P->>P: normalisasi nama header ke lowercase
    P->>D: new UACHData(headers, true)
    P->>I: getBrowser, getCPU, getDevice, getEngine, getOS
    I->>I: parseUA dari UA string
    C->>I: withClientHints()
    alt NAVIGATOR_UADATA tidak ada
        I->>I: parseCH lalu get
        I-->>C: IData sinkron
    else Chromium 85+
        I->>I: getHighEntropyValues(CH_ALL_VALUES)
        I->>D: setCH dengan UACHData(res, false)
        I->>I: parseCH lalu get
        I-->>C: Promise berisi IData
    end
%% fig: Siklus withClientHints pada dua lingkungan
%% desc: Header dipetakan sekali saat konstruksi, lalu withClientHints memilih jalur sinkron di server atau jalur promise lewat getHighEntropyValues di Chromium.
Fig. 1: Siklus withClientHints pada dua lingkunganHeader dipetakan sekali saat konstruksi, lalu withClientHints memilih jalur sinkron di server atau jalur promise lewat getHighEntropyValues di Chromium.

⚠️ setCH() mengganti uaCH pada UAItem yang sama, dan cabang browser mengembalikan Promise. Tanpa await atau .then(), field hasil masih berisi nilai dari parseUA() saja. src/main/ua-parser.js:1247-1250 src/main/ua-parser.js:1128-1146

UACHData: dari header mentah ke properti

UACHData menginisialisasi sembilan properti dari CH_ALL_VALUES menjadi undefined, lalu mengisinya dari header bila isHttpUACH bernilai true. Bila false, properti dengan nama yang sama disalin dari objek res milik getHighEntropyValues. src/main/ua-parser.js:1204-1224 src/main/ua-parser.js:63-79

KonstantaNama headerPropertiCara baca
CHsec-ch-uabrandsitemListToArray
CH_FULL_VER_LISTsec-ch-ua-full-version-listfullVersionListitemListToArray
CH_ARCHsec-ch-ua-archarchitecturenormalizeHeaderValue
CH_BITNESSsec-ch-ua-bitnessbitnessnormalizeHeaderValue
CH_FORM_FACTORSsec-ch-ua-form-factorsformFactorsitemListToArray
CH_MOBILEsec-ch-ua-mobilemobile?1 diuji dengan regex
CH_MODELsec-ch-ua-modelmodelnormalizeHeaderValue
CH_PLATFORMsec-ch-ua-platformplatformnormalizeHeaderValue
CH_PLATFORM_VERsec-ch-ua-platform-versionplatformVersionnormalizeHeaderValue

src/main/ua-parser.js:63-79 src/main/ua-parser.js:1207-1218

itemListToArray membuang tanda kutip lewat normalizeHeaderValue, memecah nilai pada ,, lalu memecah setiap token pada ;v= sehingga menghasilkan { brand, version }; token tanpa ;v= disimpan sebagai string biasa. normalizeHeaderValue hanya menerima string, membuang ", dan memotong nilai pada UA_MAX_LENGTH (500 karakter). src/main/ua-parser.js:170-183 src/main/ua-parser.js:190-192 src/main/ua-parser.js:22-24

Karena itu nilai kosong seperti 'sec-ch-ua-full-version' : '""' atau 'sec-ch-ua-arch' : '""' menjadi string kosong, bukan versi atau arsitektur, sehingga field terkait tidak terisi. test/unit/ua-ch.js:156-176

Pemetaan ke field hasil lewat parseCH

parseCH() bercabang menurut itemType dan hanya menulis field yang sumbernya tersedia. src/main/ua-parser.js:1320-1352

itemTypeSumber hintsAksi
BROWSER, ENGINEfullVersionList, fallback brandsmelewati brand yang cocok /not.a.brand/i, memetakan nama lewat browserHintsMap, versi engine diambil dari entri Chromium
CPUarchitecture, bitnessmenambahkan akhiran 64 bila bitness == '64', lalu mem-parse ulang archName + ';' dengan rgxMapper
DEVICEmobile, model, formFactorsmobile menetapkan mobile; model memicu parse ulang 'droid 9; ' + model + ')' untuk vendor/type; formFactors dipetakan lewat formFactorsMap
OSplatform, platformVersion, modelWindows: majorize versi platform 13 atau lebih menjadi '11', selain itu '10'; model == 'Xbox' mengubah nama menjadi Xbox
RESULTsemua di atasmemanggil setCH(uaCH).parseCH().get() pada tiap sub-item

src/main/ua-parser.js:1320-1352 src/main/ua-parser.js:1353-1359 src/main/ua-parser.js:1360-1389 src/main/ua-parser.js:1390-1403 src/main/ua-parser.js:1404-1417

Urutan entri brand tidak menentukan hasil. browserHintsMap memetakan nama brand ke nama kanonik seperti Chrome ke Google Chrome dan Edge ke Microsoft Edge, sehingga rangkaian Not_A Brand, Chromium, Google Chrome, Microsoft Edge dalam urutan apa pun tetap menghasilkan Edge bila hadir, lalu Chrome, lalu Chromium. src/main/ua-parser.js:331-341 test/unit/ua-ch.js:178-222

formFactorsMap memetakan form factor ke device.type; kunci ? meliputi Desktop dan Unknown dan strMapper mengembalikan undefined untuk kunci itu, sehingga "Unknown" tidak menetapkan tipe. src/main/ua-parser.js:320-329 src/main/ua-parser.js:285-300 test/unit/ua-ch.js:128-154

Header sec-ch-ua-model saja sudah cukup untuk mengisi device.model, device.vendor, dan device.type, misalnya model Xbox menghasilkan vendor Microsoft dengan tipe console. test/unit/ua-ch.js:405-416

graph TD
    H1["brands dan fullVersionList"] --> B["BROWSER, ENGINE: browserHintsMap"]
    H2["architecture dan bitness"] --> C["CPU: rgxMapper archName plus titik koma"]
    H3["mobile, model, formFactors"] --> D["DEVICE: formFactorsMap dan parse ulang model"]
    H4["platform dan platformVersion"] --> O["OS: Windows versi 13 ke atas jadi 11"]
    UA["parseUA dari UA string"] --> R["IData hasil"]
    B --> R
    C --> R
    D --> R
    O --> R
    X["Field hints kosong atau undefined"] -.-> R
    style H1 fill:#8b5cf6,color:#fff
    style H2 fill:#8b5cf6,color:#fff
    style H3 fill:#8b5cf6,color:#fff
    style H4 fill:#8b5cf6,color:#fff
    style B fill:#f59e0b,color:#000
    style C fill:#f59e0b,color:#000
    style D fill:#f59e0b,color:#000
    style O fill:#f59e0b,color:#000
    style UA fill:#2d7d46,color:#fff
    style R fill:#336791,color:#fff
    style X fill:#dc2626,color:#fff
%% fig: Alur properti UACHData ke field hasil
%% desc: Setiap itemType membaca properti hints tertentu lalu menulis field-nya sendiri, sementara nilai dari parseUA tetap menjadi isi awal dan menjadi cadangan saat field hints kosong.
Fig. 2: Alur properti UACHData ke field hasilSetiap itemType membaca properti hints tertentu lalu menulis field-nya sendiri, sementara nilai dari parseUA tetap menjadi isi awal dan menjadi cadangan saat field hints kosong.

Fallback ke UA string

parseCH() hanya menetapkan field yang sumber hints-nya ada, sehingga nilai hasil parseUA() yang dijalankan sebelumnya tetap dipakai ketika hints tidak lengkap. Pada contoh dengan hanya sec-ch-ua-mobile: ?1, nama dan versi browser tetap berasal dari UA string, sementara device.type menjadi mobile. test/unit/ua-ch.js:76-96

FieldNilaiSumber
browser.nameChromeUA string
browser.version110.0.0.0UA string
cpu.architecturex86_64UA string
device.typemobilesec-ch-ua-mobile
device.model, device.vendorundefinedtidak ada hints

Tanpa pemanggilan withClientHints() sama sekali, seluruh header sec-ch-ua* diabaikan dan semua field berasal dari UA string: versi 110.0.0.0, arsitektur x86_64, serta device.type, device.model, dan device.vendor yang undefined. test/unit/ua-ch.js:54-74

Sebaliknya, bila hints tersedia nilainya menang atas UA string. Pada contoh, UA string menyebut Chrome/110.0.0.0 tetapi header versi menyebut 93.0.1.2, sehingga hasilnya browser.version 93.0.1.2, cpu.architecture arm64, os.version 11 untuk sec-ch-ua-platform-version "13", serta device.model Pixel 99 dengan vendor Google. test/unit/ua-ch.js:8-52

Data uji berbentuk tabel UACHTests dengan field desc, headers, dan expect dipakai untuk memverifikasi deteksi brand yang hanya bersumber dari sec-ch-ua, lalu setiap entri diuji dengan UAParser(test.headers).withClientHints(). test/data/ua-ch/headers.js:1-15 test/unit/ua-ch.js:225-232

Untuk menggabungkan pembacaan hints dengan pemeriksaan fitur, lihat Feature Check dan Perbandingan Hasil.