谈谈检测浏览器类型

前几天被问到如何检测浏览器类型,我突然发现我对此并不了解,之前的项目中也没有使用到过,只隐约记得通过一个自带的方法即可获取。所以今天特意来仔细补习一下。

核心: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.mzph.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的规定来编写 自定制 官网&…