談談檢測瀏覽器類型

前幾天被問到如何檢測瀏覽器類型,我突然發現我對此并不了解,之前的項目中也沒有使用到過,只隱約記得通過一個自帶的方法即可獲取。所以今天特意來仔細補習一下。

核心:navigator.userAgent

1.正則表達式

2.引用外部庫

3.判斷瀏覽器的其他特性

一.首先講一下navigator.userAgent

navigator.userAgent 是一個包含用戶代理字符串(User Agent String)的屬性,這個字符串提供了關于用戶瀏覽器操作系統設備的信息。用戶代理字符串的生成和傳遞涉及瀏覽器和服務器之間的通信過程。

用戶代理字符串包含主要內容:

-用戶瀏覽器

-操作系統

-設備信息

接下來從構成、生成原理、傳遞解析和局限性幾個方面來講解一下用戶代理字符串:

1.1用戶代理字符串的構成

  1. 瀏覽器名稱和版本:標識瀏覽器的名稱和版本號。【這個內容導致經常用于判斷瀏覽器類型場景上!】
  2. 操作系統:標識用戶使用的操作系統及其版本。
  3. 渲染引擎:標識瀏覽器使用的渲染引擎。
  4. 設備信息:標識設備類型(比如手機、平板、桌面)。
舉個例子
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36

我們來分析一下這個例子用戶代理字符串中包含了哪些信息呢

  • Mozilla/5.0:兼容性標識符,表示兼容 Mozilla 的瀏覽器。
  • (Windows NT 10.0; Win64; x64):操作系統信息,表示 Windows 10 64 位操作系統。
  • AppleWebKit/537.36:渲染引擎,表示使用 WebKit 內核。
  • (KHTML, like Gecko):表示兼容 Gecko 內核。
  • Chrome/92.0.4515.107:瀏覽器名稱和版本號,表示 Chrome 92。
  • Safari/537.36:表示兼容 Safari 537.36。【這里注意,正則判斷時,由于兼容性標識,也有可能chrome瀏覽器識別到safari字段】

1.2用戶代理字符串的生成

  1. 瀏覽器內部生成
    • 瀏覽器在初始化時,根據其內置的信息和用戶的操作系統,生成用戶代理字符串。
    • 這些信息通常在瀏覽器的配置文件中定義,瀏覽器開發者在開發時設定。
  1. 用戶定制
    • 某些瀏覽器允許用戶通過設置或擴展自定義用戶代理字符串。用戶可以修改用戶代理字符串以偽裝成不同的瀏覽器或設備。【這一點導致了他的不可靠性】

1.3用戶代理字符串的傳遞(瀏覽器和服務端之間)

  1. HTTP 請求
    • 當用戶訪問網頁時,瀏覽器會發送 HTTP 請求到服務器。在請求頭中包含一個名為User-Agent的字段,攜帶用戶代理字符串。
    • 示例 HTTP 請求頭:
GET / HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36
  1. 服務器處理
    • 服務器接收到請求后,可以讀取User-Agent字段,解析用戶代理字符串以了解客戶端的瀏覽器、操作系統和設備信息。
    • 基于這些信息,服務器可以返回相應的內容或進行特定的處理,如返回適配移動設備的網頁。

1.4用戶代理字符串的解析

知道了用戶代理字符串的內容之后,我們需要把他運用到實處,那么很重要的一點就是如何對其進行解析!

  1. 前端解析
    • 在前端 JavaScript 代碼中,可以通過navigator.userAgent獲取用戶代理字符串,并使用正則表達式字符串匹配解析其中的信息。【這也是下一節要重點講的內容之一】
    • 示例代碼:
const userAgent = navigator.userAgent;
console.log(userAgent); // 輸出用戶代理字符串
  1. 后端解析
    • 在服務器端,可以使用編程語言(如 Python、Java、Node.js)解析用戶代理字符串,進行用戶設備和瀏覽器的識別。
    • 示例代碼(Node.js):
const http = require('http');http.createServer((req, res) => {const userAgent = req.headers['user-agent'];console.log(userAgent); // 輸出用戶代理字符串res.writeHead(200, {'Content-Type': 'text/plain'});res.end('Hello World\n');
}).listen(8080);

1.5用戶代理字符串的局限性

  1. 不可靠性
    • 用戶代理字符串可以被用戶修改或偽裝,因此基于其進行的判斷不總是可靠的。
    • 某些瀏覽器或擴展允許用戶自定義用戶代理字符串,導致誤判。
  1. 復雜性和變化
    • 用戶代理字符串格式復雜且隨時間變化,不同瀏覽器和版本的格式可能不同。
    • 解析用戶代理字符串需要持續更新解析規則,以應對新瀏覽器和版本的變化。
  1. 特性檢測優先
    • 現代 Web 開發推薦使用特性檢測,而不是依賴用戶代理字符串。特性檢測直接檢測瀏覽器是否支持特定功能,更加可靠。
    • 示例代碼(特性檢測):
if ('geolocation' in navigator) {console.log('Geolocation is supported');
} else {console.log('Geolocation is not supported');
}

二.學習完用戶代理字符串,回到正題,如何判斷瀏覽器類型

  • 正則表達式
  • match結合正則表達式
  • 第三方庫(最簡單便捷)
  • 條件注釋(老方法了,了解即可)
  • 判斷特性(最推薦最可靠的!)

2.1直接使用正則表達式匹配 navigator.userAgent

function getBrowserType() {const userAgent = navigator.userAgent;if (userAgent.indexOf("Firefox") > -1) {return "Firefox";} else if (userAgent.indexOf("SamsungBrowser") > -1) {return "Samsung Internet";} else if (userAgent.indexOf("Opera") > -1 || userAgent.indexOf("OPR") > -1) {return "Opera";} else if (userAgent.indexOf("Trident") > -1) {return "Internet Explorer";} else if (userAgent.indexOf("Edge") > -1) {return "Microsoft Edge";} else if (userAgent.indexOf("Chrome") > -1) {return "Chrome";} else if (userAgent.indexOf("Safari") > -1) {return "Safari";} else {return "Unknown";}
}console.log(getBrowserType());
  • navigator.userAgent獲取了用戶代理字符串。
  • indexOf方法用于檢查字符串中是否包含特定的子字符串。如果包含,返回子字符串在字符串中的第一個索引,否則返回 -1
  • 判斷不同瀏覽器標志來返回相應的瀏覽器類型。

這個方法簡單直觀,容易理解,是學習了用戶代理字符串后最容易想到的方法之一,但是卻不可靠,首先利用indexOf會存在大小寫敏感問題,其次這么多的ifelse也使得維護工作做起來很困難。

2.2 match() 結合正則表達式

function getBrowserType() {const userAgent = navigator.userAgent;if (userAgent.match(/Firefox/i)) {return "Firefox";} else if (userAgent.match(/SamsungBrowser/i)) {return "Samsung Internet";} else if (userAgent.match(/Opera|OPR/i)) {return "Opera";} else if (userAgent.match(/Trident/i)) {return "Internet Explorer";} else if (userAgent.match(/Edge/i)) {return "Microsoft Edge";} else if (userAgent.match(/Chrome/i)) {return "Chrome";} else if (userAgent.match(/Safari/i)) {return "Safari";} else {return "Unknown";}
}console.log(getBrowserType());
  • match()方法在字符串中執行一個搜索匹配,并返回匹配結果的數組,如果沒有找到匹配,則返回null。
  • 正則表達式中的i標志表示不區分大小寫。(規避了直接使用indexOf大小寫敏感問題)

這個方法其實和第一種差不多,而且正則表達式提供了更強的匹配能力,處理起來更靈活,但是大部分人對于正則表達式還是做不到說寫就寫的,所以對于不熟悉正則表達式的開發者可能有一定的學習成本。

2.3使用第三方庫(如 bowser

import Bowser from "bowser";function getBrowserType() {const browser = Bowser.getParser(window.navigator.userAgent);return browser.getBrowserName();
}console.log(getBrowserType());
  • Bowser是一個 JavaScript 庫,用于解析用戶代理字符串,并提供 API 來獲取瀏覽器和操作系統信息。
  • Bowser.getParser(userAgent)創建一個解析器對象。
  • parser.getBrowserName()返回瀏覽器名稱

這種方法應該是很多人會選擇使用的,直接使用第三方庫,減少了自行編寫和維護代碼的工作量,而且庫本身就提供了豐富的功能和良好的兼容性。但是呢顯而易見需要引入額外的第三方庫,也是增加了項目的依賴。

2.4使用條件注釋(了解即可)

<script>var isIE = false;/*@cc_on@if (@_jscript_version)isIE = true;@end@*/if (isIE) {console.log("Internet Explorer");} else {console.log("Not Internet Explorer");}
</script>
  • 條件注釋是 Internet Explorer 的一種特性,允許在 HTML 注釋中包含條件代碼。
  • @cc_on是開啟條件編譯的指令。
  • @_jscript_version是一個 JScript 變量,表示當前 JScript 引擎的版本。
  • 這種方法僅適用于 Internet Explorer,且現代瀏覽器不再支持條件注釋。

2.5基于特性檢測(最準確最推薦!)

function isIE() {return !!window.ActiveXObject || "ActiveXObject" in window;
}
function isEdge() {return !isIE() && !!window.StyleMedia;
}
if (isIE()) {console.log("Internet Explorer");
} else if (isEdge()) {console.log("Microsoft Edge");
} else {console.log("Not Internet Explorer or Edge");
}
  • 基于特性檢測是通過檢測特定瀏覽器的特性來判斷瀏覽器類型,而不是依賴于userAgent
  • window.ActiveXObject"ActiveXObject" in window用于檢測 Internet Explorer。
  • window.StyleMedia用于檢測 Microsoft Edge。

這個方更加可靠,不依賴userAgent,避免了用戶代理字符串可能被篡改的問題。(規避了不可靠性),但是缺點也很明顯,需要知道每種瀏覽器特有的特性,增加了復雜性。

三、應用場景

對于我個人的項目經歷來說,之前是幾乎沒有用到過瀏覽器類型判斷的,所以,我還去了解了一下需要用到瀏覽器類型判斷的一些應用場景。

3.1 瀏覽器特性檢測和兼容性處理

最容易想到的第一個應用場景,就是對兼容性的處理。某些瀏覽器對特定的功能或 API 支持不一致。需要通過檢測用戶代理字符串,可以針對特定瀏覽器執行不同的代碼,來確保功能的兼容性。

const userAgent = navigator.userAgent;if (userAgent.match(/Trident/i)) {// 針對 Internet Explorer 的特定處理
} else if (userAgent.match(/Edge/i)) {// 針對 Microsoft Edge 的特定處理
} else if (userAgent.match(/Chrome/i)) {// 針對 Chrome 的特定處理
} else if (userAgent.match(/Safari/i)) {// 針對 Safari 的特定處理
}

3.2 響應式設計和設備檢測

第二個我想到的就是響應式,因為之前經常在項目中使用媒體查詢去實現響應式涉及,我們知道很多頁面在移動設備和桌面設備之間是不同的布局和功能。所以我們通常需要通過檢測用戶代理字符串,確定用戶是否在使用移動設備,從而去調整頁面布局和交互方式。

const userAgent = navigator.userAgent;if (/Mobi|Android/i.test(userAgent)) {// 針對移動設備的布局和交互處理
} else {// 針對桌面設備的布局和交互處理
}

3.3 分析和統計

對于一些數據埋點,有時候可能還需要考慮到觸發時所在的環境,在網站分析和統計中,收集用戶代理字符串信息可以幫助開發者了解用戶的瀏覽器和設備使用情況,這個對于開發者是很有好處的。可以作為性能優化的量化依據。

// 將用戶代理字符串發送到分析服務器
sendUserAgentToAnalytics(navigator.userAgent);function sendUserAgentToAnalytics(userAgent) {// 發送數據到服務器的代碼
}

還有一些收集來的運用場景,自己想可能不太會想的到,不過看完之后就會覺得確實了:

3.4. 功能降級

某些情況有些特定功能可能不能再在某些瀏覽器使用。也可以通過檢測用戶代理字符串,·去選擇替代方案。

再說直白點就比如很多用戶使用很老的版本的設備或者未更新系統之類的,這里就可以運用到。

const userAgent = navigator.userAgent;if (userAgent.match(/MSIE|Trident/i)) {// 提供替代方案或警告用戶使用現代瀏覽器alert("Your browser is not supported. Please upgrade to a modern browser.");
}

5. 動態加載資源

涉及到資源加載優化了,很多時候不同設備下的靜態資源是截然不同的,可以根據用戶的瀏覽器和設備類型,動態加載不同的資源(如 CSS、JavaScript 文件),以優化性能和用戶體驗。

<script>const userAgent = navigator.userAgent;if (/Mobi|Android/i.test(userAgent)) {// 加載移動設備的樣式表document.write('<link rel="stylesheet" href="mobile.css">');} else {// 加載桌面設備的樣式表document.write('<link rel="stylesheet" href="desktop.css">');}
</script>

6. 調試和日志記錄

在調試和日志記錄中,記錄用戶代理字符串可以幫助開發者了解用戶的瀏覽器環境,從而更快地定位和解決問題。

console.log("User Agent: " + navigator.userAgent);// 將用戶代理字符串記錄到日志服務器
logUserAgent(navigator.userAgent);function logUserAgent(userAgent) {// 記錄數據到服務器的代碼
}

完。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/37961.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/37961.shtml
英文地址,請注明出處:http://en.pswp.cn/web/37961.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Android面試八股文】你知道什么是冷啟動和熱啟動嗎?你知道應用冷啟動的全流程嗎?你知道如何解決啟動時候的黑白屏問題?

文章目錄 一、冷啟動、熱啟動的概念二、冷啟動的流程冷啟動啟動流程:流程細節三、如何解決啟動時候的黑白屏問題?一、冷啟動、熱啟動的概念 在Android開發中,冷啟動和熱啟動是兩個重要的概念,它們描述了應用程序啟動時不同的狀態和表現: 冷啟動(Cold Start): 冷啟動指…

記一次kafka使用不當導致的服務器異常

一、背景 1.運維反饋服務器cpu高&#xff0c;且高達80% 2.經過排查發現kafka出現消息積壓情況 3.使用的是springboot kafka框架 dependency><groupId>org.springframework.kafka</groupId><artifactId>spring-kafka</artifactId> </dependency…

Linux-網絡安全私房菜

文章目錄 前言入門基本指令篇章字符集設置cdlsdatemkdirtouch-d-m 修改主機名rmshredrename重命名mv移動tar打包與壓縮打包但是不壓縮打包且壓縮更新包文件解壓對應的包 zip壓縮文件命令cat查看顯示行號交互寫入&#xff08;追加&#xff09;顯示空行 more和lesshead和tailhead…

Android的懸浮時鐘(一)

在Android&#xff0c;如果要懸浮在其他應用上方顯示時鐘或者其他界面的話是需要申請權限的。 首先在manifest中我們就要寫自己要申請的權限SYSTEM_ALERT_WINDOW <uses-permission android:name"android.permission.SYSTEM_ALERT_WINDOW" /> 不同于請求照片或…

期末復習---程序填空

注意&#xff1a; 1.數組后移 *p *(p-1) //把前一個數賦值到后一個數的位置上來覆蓋后一個數 2.指針找最大字符 max *p while( *p){ if( max< *p) { max*p; qp;/ 用新的指針指向這個已經找到的最大位置&#xff1b;!!!!!!!!! } p; //因為開始沒有next &#xff…

Web工程化

1、webpack 1.1 概念 一個前端打包器。 webpack 只識別javascript. 所以需要安裝nodejs環境。 1.2 運行環境 Nodejs Nodejs 是運行JavaScript的環境。 因為nodejs發布了許多版本&#xff0c;在不同的技術棧下&#xff0c;需要使用不同的nodejs。 所以需要在電腦上安裝n…

web應用技術-第十一次課后作業

驗證過濾器進行權限驗證的原理。 Filter過濾器&#xff1a;可以把對資源的請求攔截下來&#xff0c;從而實現一些特殊的功能。一般完成登錄校驗、統一編碼處理、敏感字符處理等通用操作。 定義&#xff1a;實現Filter接口 配置&#xff1a;WebFilter(urlPatterns"/*&qu…

常見VPS主機術語有哪些?VPS術語解析

常見VPS主機術語有哪些&#xff1f;本期為大家解析一下我們常見到的聽到的VPS專業術語&#xff0c;幫助大家更輕松的了解VPS主機相關知識。 常見VPS主機術語 Apache – 世界上最流行的 Web 服務器軟件。 CentOS – 旨在提供基于 Red Hat Enterprise Linux 的企業級操作系統的…

mysql 主主HA高可用方案詳解

1.環境準備&#xff1a; 主機&#xff1a;1921.4,1921.5 操作系統&#xff1a;centos 7.3 mysql數據庫版本&#xff1a;mysql 5.7.13 浮動IP:1921.182 2.mysql 下載及解壓安裝配置 2.1 下載&#xff1a; #wget http://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.13-linu…

easyexcel 模板填充Excel數據,實現自定義換行及動態調整行高,并保持列表格式一致

pom依賴&#xff1a; <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.5</version> </dependency><dependency><groupId>com.alibaba</groupId><artifa…

數據結構-線性表的應用

目錄 前言一、有序表的合并1.1 順序表實現1.2 單鏈表實現 二、稀疏多項式的相加和相乘2.1 稀疏多項式的相加2.2 稀疏多項式的相乘 總結 前言 本篇文章介紹線性表的應用&#xff0c;分別使用順序表和單鏈表實現有序表的合并&#xff0c;最后介紹如何使用單鏈表實現兩個稀疏多項…

基于springboot+vue+uniapp的超市售貨管理平臺

開發語言&#xff1a;Java框架&#xff1a;springbootuniappJDK版本&#xff1a;JDK1.8服務器&#xff1a;tomcat7數據庫&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;數據庫工具&#xff1a;Navicat11開發軟件&#xff1a;eclipse/myeclipse/ideaMaven包&#…

考研生活day2--王道課后習題2.3.1、2.3.2、2.3.3

2.3.1 題目描述&#xff1a; 這題和曾經做過的LeetCode203.移除元素一模一樣&#xff0c;所以我們就使用LeetCode進行書寫&#xff0c;題目鏈接203. 移除鏈表元素 - 力扣&#xff08;LeetCode&#xff09; 解題思路 大家的第一反應肯定是根據書上所學的書寫方法一樣書寫&…

【PB案例學習筆記】-26制作一個帶浮動圖標的工具欄

寫在前面 這是PB案例學習筆記系列文章的第26篇&#xff0c;該系列文章適合具有一定PB基礎的讀者。 通過一個個由淺入深的編程實戰案例學習&#xff0c;提高編程技巧&#xff0c;以保證小伙伴們能應付公司的各種開發需求。 文章中設計到的源碼&#xff0c;小凡都上傳到了gite…

爬蟲cookie是什么意思

“爬蟲 cookie”指的是網絡爬蟲在訪問網站時所使用的cookie&#xff0c;網絡爬蟲是一種自動化程序&#xff0c;用于在互聯網上收集信息并進行索引&#xff0c;這些信息可以用于搜索引擎、數據分析或其他目的。 本教程操作系統&#xff1a;Windows10系統、Dell G3電腦。 “爬蟲…

51-1 內網信息收集 - 內網資源探測

導語 在內網滲透過程中,通常需要利用各種技術來探測內網資源,為后續的橫向滲透做準備。發現內網存活的主機及其詳細信息可以幫助確定攻擊方向和潛在的漏洞。 一、基于 ICMP 發現存活主機 ICMP(Internet Control Message Protocol,因特網控制消息協議)是 TCP/IP 協議簇的…

一段式、二段式和三段式狀態機的特點及適用情況:

在FPGA設計中,狀態機的選擇主要取決于具體應用場景和設計需求。 一段式狀態機: 優點: 結構簡單,易于理解和實現占用資源少時序邏輯簡單,延遲小 缺點: 組合邏輯復雜度高可能存在毛刺問題不易于大規模狀態機的設計 適用場景: 簡單的控制邏輯狀態數量較少的場合對時序要求較…

React+TS前臺項目實戰(二十二)-- 全局常用導出組件Export封裝

文章目錄 前言Export組件1. 功能分析2. 代碼詳細注釋3. 使用方式4. 效果展示 總結 前言 今天我們來封裝一個帶導出圖標的導出組件。 Export組件 1. 功能分析 通過傳入鏈接地址&#xff0c;規定要跳轉的導出頁面&#xff0c;或是直接通過鏈接導出數據 2. 代碼詳細注釋 // /c…

虛擬環境管理

虛擬環境 在使用 Python 時我們一般使用“pip install 第三方包名”來安裝第三方包&#xff0c;但是由于pip的特性&#xff0c;系統只能安裝每個包的一個版本。而在實際開發中&#xff0c;可能同時開發多個項目&#xff0c;如&#xff1a;上圖有三個項目&#xff1b;每個項目需…

django學習入門系列之第三點《BootSrap初了解》

文章目錄 初識BootStrap往期回顧 初識BootStrap BootSrap是什么&#xff1f; 是別人幫我們已寫好的CSS樣式&#xff0c;我們如果想要使用這個BootSrap&#xff1a; 下載BootStrap使用 在頁面上引入BootStrap編寫HTML時&#xff0c;按照BootStrap的規定來編寫 自定制 官網&…