使用 Yauaa 解析用戶代理
1. 概述
在建立 Web 應用程式時,我們經常需要有關存取我們的應用程式的裝置和瀏覽器的信息,以便我們可以提供最佳化的使用者體驗。
使用者代理程式是一個字串,用於標識向我們的伺服器發出請求的客戶端。它包含有關客戶端設備、作業系統、瀏覽器等的資訊。它透過User-Agent
請求標頭髮送到伺服器。
然而,由於用戶代理字串的結構複雜且性質多樣,解析用戶代理字串可能具有挑戰性。 Yauaa(又一個 UserAgent 分析器)庫有助於簡化在 Java 生態系統中工作時的此過程。
在本教程中,我們將探索如何在 Spring Boot 應用程式中利用 Yauaa 來解析使用者代理字串並實現特定於裝置的路由。
2. 設定項目
在深入實施之前,我們需要包含 SDK 依賴項並正確配置我們的應用程式。
2.1.依賴關係
讓我們先將yauaa 依賴項新增到專案的pom.xml
檔案中:
<dependency>
<groupId>nl.basjes.parse.useragent</groupId>
<artifactId>yauaa</artifactId>
<version>7.28.1</version>
</dependency>
這種依賴關係為我們提供了必要的類別來解析和分析應用程式中的使用者代理請求標頭。
2.2.定義UserAgentAnalyzer
設定 Bean
現在我們已經新增了正確的依賴項,讓我們定義UserAgentAnalyzer
bean:
private static final int CACHE_SIZE = 1000;
@Bean
public UserAgentAnalyzer userAgentAnalyzer() {
return UserAgentAnalyzer
.newBuilder()
.withCache(CACHE_SIZE)
// ... other settings
.build();
}
UserAgentAnalyzer
類別是解析使用者代理字串的主要入口點。
預設情況下, UserAgentAnalyzer
使用大小為10000,
但我們可以使用withCache()
方法根據需要更新它,就像我們在範例中所做的那樣。快取透過避免重複解析相同的用戶代理字串來幫助我們提高效能。
3. 探索UserAgent
字段
一旦定義了UserAgentAnalyzer
bean,我們就可以使用它來解析使用者代理字串並取得有關客戶端的資訊。
為了進行演示,我們採用用於編寫本教程的設備的用戶代理:
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Safari/605.1.15
現在,我們將使用UserAgentAnalyzer
bean 來解析上述內容並提取所有可用欄位:
UserAgent userAgent = userAgentAnalyzer.parse(USER_AGENT_STRING);
userAgent
.getAvailableFieldNamesSorted()
.forEach(fieldName -> {
log.info("{}: {}", fieldName, userAgent.getValue(fieldName));
});
讓我們來看看執行上面程式碼時產生的日誌:
com.baeldung.Application : DeviceClass: Desktop
com.baeldung.Application : DeviceName: Apple Macintosh
com.baeldung.Application : DeviceBrand: Apple
com.baeldung.Application : DeviceCpu: Intel
com.baeldung.Application : DeviceCpuBits: 64
com.baeldung.Application : OperatingSystemClass: Desktop
com.baeldung.Application : OperatingSystemName: Mac OS
com.baeldung.Application : OperatingSystemVersion: >=10.15.7
com.baeldung.Application : OperatingSystemVersionMajor: >=10.15
com.baeldung.Application : OperatingSystemNameVersion: Mac OS >=10.15.7
com.baeldung.Application : OperatingSystemNameVersionMajor: Mac OS >=10.15
com.baeldung.Application : LayoutEngineClass: Browser
com.baeldung.Application : LayoutEngineName: AppleWebKit
com.baeldung.Application : LayoutEngineVersion: 605.1.15
com.baeldung.Application : LayoutEngineVersionMajor: 605
com.baeldung.Application : LayoutEngineNameVersion: AppleWebKit 605.1.15
com.baeldung.Application : LayoutEngineNameVersionMajor: AppleWebKit 605
com.baeldung.Application : AgentClass: Browser
com.baeldung.Application : AgentName: Safari
com.baeldung.Application : AgentVersion: 17.6
com.baeldung.Application : AgentVersionMajor: 17
com.baeldung.Application : AgentNameVersion: Safari 17.6
com.baeldung.Application : AgentNameVersionMajor: Safari 17
com.baeldung.Application : AgentInformationEmail: Unknown
com.baeldung.Application : WebviewAppName: Unknown
com.baeldung.Application : WebviewAppVersion: ??
com.baeldung.Application : WebviewAppVersionMajor: ??
com.baeldung.Application : WebviewAppNameVersion: Unknown
com.baeldung.Application : WebviewAppNameVersionMajor: Unknown
com.baeldung.Application : NetworkType: Unknown
正如我們所看到的, UserAgent
類別提供了有關設備、作業系統、瀏覽器等的有價值的資訊。我們可以使用這些欄位並根據我們的業務需求做出明智的決策。
同樣重要的是要注意,並非所有欄位都可用於給定的使用者代理字串,這可以透過Unknown
和??
明顯看出。日誌語句中的值。如果我們不想顯示這些不可用的值,可以使用UserAgent
類別的getCleanedAvailableFieldNamesSorted()
方法。
4. 實現基於設備的路由
現在我們已經了解了UserAgent
類別中可用的各個字段,讓我們透過在應用程式中實現基於設備的路由來使用這些知識。
對於我們的演示,我們將假設需要將我們的應用程式提供給行動設備,同時限制對非行動裝置的存取。我們可以透過檢查用戶代理字串的DeviceClass
欄位來實現這一點。
首先,讓我們定義一個受支援的設備類別列表,我們將其視為行動裝置:
private static final List SUPPORTED_MOBILE_DEVICE_CLASSES = List.of("Mobile", "Tablet", "Phone");
接下來,讓我們建立控制器方法:
@GetMapping("/mobile/home")
public ModelAndView homePage(@RequestHeader(HttpHeaders.USER_AGENT) String userAgentString) {
UserAgent userAgent = userAgentAnalyzer.parse(userAgentString);
String deviceClass = userAgent.getValue(UserAgent.DEVICE_CLASS);
boolean isMobileDevice = SUPPORTED_MOBILE_DEVICE_CLASSES.contains(deviceClass);
if (isMobileDevice) {
return new ModelAndView("/mobile-home");
}
return new ModelAndView("error/open-in-mobile", HttpStatus.FORBIDDEN);
}
在我們的方法中,我們使用@RequestHeader
來取得使用者代理字串的值,並使用UserAgentAnalyzer
bean 對其進行解析。然後,我們從解析的UserAgent
實例中提取DEVICE_CLASS
字段,並檢查它是否與任何受支援的行動裝置類別相符。
如果我們確定傳入請求是從行動裝置發出的,我們將返回/mobile-home
視圖。否則,我們將傳回 HTTP 狀態為「禁止」的錯誤視圖,表示該資源只能從行動裝置存取。
5. 測試基於設備的路由
現在我們已經實現了基於設備的路由,讓我們使用 MockMvc 測試它以確保它按預期工作:
`private static final String SAFARI_MAC_OS_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15";
mockMvc.perform(get("/mobile/home")
.header("User-Agent", SAFARI_MAC_OS_USER_AGENT))
.andExpect(view().name("error/open-in-mobile"))
.andExpect(status().isForbidden());`
我們使用 macOS 的 Safari 使用者代理字串模擬請求並呼叫我們的/home
端點。我們驗證了錯誤視圖已傳回給客戶端,HTTP 狀態為 403 禁止。
同樣,現在讓我們使用行動用戶代理來呼叫我們的端點:
`private static final String SAFARI_IOS_USER_AGENT = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1";
mockMvc.perform(get("/mobile/home")
.header("User-Agent", SAFARI_IOS_USER_AGENT))
.andExpect(view().name("/mobile-home"))
.andExpect(status().isOk());`
在這裡,我們使用適用於 iOS 的 Safari 使用者代理字串,並斷言請求已成功完成,並將正確的視圖傳回給客戶端。
6. 減少記憶體佔用並加快執行速度
預設情況下,Yauaa 解析使用者代理字串中的所有可用欄位。但是,如果我們只需要應用程式中的欄位子集,我們可以在UserAgentAnalyzer
bean 中指定它們:
UserAgentAnalyzer
.newBuilder()
.withField(UserAgent.DEVICE_CLASS)
// ... other settings
.build();
在這裡,我們將UserAgentAnalyzer
配置為僅解析我們在基於設備的路由實作中使用的DEVICE_CLASS
欄位。
如果我們需要解析多個字段,我們可以將多個withField()
方法連結在一起。強烈推薦這種方法,因為它有助於減少記憶體使用並提高效能。
七、結論
在本文中,我們探索了使用 Yauaa 來解析和分析用戶代理字串。
我們完成了必要的配置,查看了我們可以訪問的不同字段,並在我們的應用程式中實現了基於設備的路由。
與往常一樣,本文中使用的所有程式碼範例都可以在 GitHub 上找到。