Googlebooks 基于 Android 技术堆栈构建,并与 ChromeOS 的桌面基础架构配对。大多数 Web 应用在 Googlebooks 上运行的效果应与在任何其他桌面设备上运行的效果相同,并且会看到与 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 图书(例如,用于分析),或者引导用户下载兼容的 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),这是一个高熵提示,可提供指定设备的逗号分隔列表的设备规格(桌面设备、平板电脑、移动设备、车载设备等)。虽然这通常是单一的外形规格,但可以包含所有适用的外形规格,因此可拆卸设备可能会返回 "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 标头后会包含关键提示,则会重试请求。这样,您就可以提供优化后的网页,而不是初始响应。由于这会增加一次额外的往返,因此仅在需要关键信息的重要网页更改时使用。