找出 Googlebook

Googlebooks 是以 Android 技術堆疊為基礎,並搭配 ChromeOS 的桌面基礎架構。大多數網頁應用程式在 Googlebook 上的執行方式,應與在其他桌上型裝置上相同,且會看到與 ChromeOS 相同的 User Agent 字串:

Mozilla/5.0 (X11; CrOS x86_64 14541.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0; Safari/537.36

如要更準確地識別 Google 圖書 (例如用於 Analytics),或引導使用者下載相容的 Android 應用程式,您需要要求兩個使用者代理程式用戶端提示:Platform 和 Mobile 用戶端提示。這兩者都是低熵提示,因此您不需要額外要求或權限,就能取得這些提示,就像您使用 User-Agent 字串一樣。你可以直接將這些規則納入現有的偵測機制。

UA-CH 標頭 Google 圖書的值
Sec-CH-UA-Platform "Android"
Sec-CH-UA-Mobile ?0 (False)

如要在瀏覽器中偵測這項功能,請使用 navigator.userAgentData API:

const isGooglebook = window?.navigator?.userAgentData?.platform === 'Android' && window?.navigator?.userAgentData?.mobile === false;

由於使用者代理程式縮減,Googlebook 專屬平台並未新增至 Platform 用戶端提示或使用者代理程式字串,因此為了確保 Googlebook 與舊版 ChromeOS 有所區別,用戶端提示已變更為 "Android",反映 Googlebook 與 Android 應用程式相容。

伺服器端偵測

由於這兩者都是低熵用戶端提示,因此系統會在用戶端發出初始要求時,將這些提示傳送至伺服器,您可以透過下列其中一種方式擷取提示:

Node.js

const platform = req.headers['sec-ch-ua-platform'] || 'Not Sent';
const mobile = req.headers['sec-ch-ua-mobile'] || 'Not Sent';

const cleanPlatform = platform.replace(/"/g, '');
const isGooglebook = cleanPlatform === 'Android' && mobile === '?0';

Java

String platform = exchange.getRequestHeaders().getFirst("Sec-CH-UA-Platform");
 if (platform == null) platform = "Not Sent";

String mobile = exchange.getRequestHeaders().getFirst("Sec-CH-UA-Mobile");
if (mobile == null) mobile = "Not Sent";

String cleanPlatform = platform.replace("\"", "");
boolean isGooglebook = cleanPlatform.equals("Android") && mobile.equals("?0");

Ruby

mobile = req['Sec-CH-UA-Mobile'] || 'Not Sent'

clean_platform = platform.gsub('"', '')
is_googlebook = clean_platform == 'Android' && mobile == '?0'

Python

platform = self.headers.get('Sec-CH-UA-Platform', 'Not Sent')
mobile = self.headers.get('Sec-CH-UA-Mobile', 'Not Sent')

clean_platform = platform.replace('"', '')
is_googlebook = clean_platform == 'Android' and mobile == '?0'

PHP

$mobile = $_SERVER['HTTP_SEC_CH_UA_MOBILE'] ?? 'Not Sent';

$cleanPlatform = str_replace('"', '', $platform);
$isGooglebook = ($cleanPlatform === 'Android' && $mobile === '?0');

Go

platform := r.Header.Get("Sec-CH-UA-Platform")
if platform == "" {
  platform = "Not Sent"
}
mobile := r.Header.Get("Sec-CH-UA-Mobile")
if mobile == "" {
  mobile = "Not Sent"
}

cleanPlatform := strings.ReplaceAll(platform, "\"", "")
isGooglebook := cleanPlatform == "Android" && mobile == "?0"

其他實用的用戶端提示

雖然 Platform 和 Mobile 用戶端提示足以讓您瞭解使用者是否使用 Googlebook,但您可能需要更多裝置資訊。 [Sec-CH-UA](https://developer.mozilla.org/docs/Web/HTTP/Reference/Headers/Sec-CH-UA) 用戶端提示會傳回以半形逗號分隔的清單,列出主要瀏覽器版本和與裝置相關聯的其他品牌,相較於從 User-Agent 字串剖析,這種做法更直接。此外,還有Form Factors用戶端提示 (Sec-CH-UA-Form-Factors),這是一種高熵提示,可提供指定裝置的板型規格逗號分隔的清單 (例如:電腦、平板電腦、行動裝置、Automotive 等)。雖然這通常是單一板型規格,但可能包含所有適用的板型規格,因此可拆卸式裝置可能會傳回 "Desktop", "Tablet"。如果需要精確瞭解使用者使用的板型規格,而不只是知道不是 Android 裝置,可以使用 Critical-CH 標頭:

GET / HTTP/1.1
Host: example.com

HTTP/1.1 200 OK
Content-Type: text/html
Accept-CH: Sec-CH-UA-Form-Factors
Vary: Sec-CH-UA-Form-Factors
Critical-CH: Sec-CH-UA-Form-Factors

如果用戶端在處理 Accept-CH 標頭後包含重要提示,系統會重試要求。這樣一來,您就能放送最佳化網頁,而非初始回應。由於這會增加額外的來回行程,因此請僅針對需要重要資訊的有意義網頁變更使用。