點(diǎn)擊關(guān)注“八戒技術(shù)團(tuán)隊(duì)”,閱讀更多技術(shù)干貨
01
那段歷史
在開發(fā)過程中,我們通常用用戶代理字符串—瀏覽器端 window.navigator.userAgent或者服務(wù)器端header攜帶的user-agent —來(lái)用于檢測(cè)當(dāng)前瀏覽器是否為移動(dòng)端, 比如:
if(isMobile()) {
// 移動(dòng)端邏輯...
}
function isMobile () {
const versions = (function () {
const u = window.navigator.userAgent // 服務(wù)器端:req.header('user-agent')
return {
trident: u.indexOf('Trident') > -1, // IE內(nèi)核
presto: u.indexOf('Presto') > -1, // opera內(nèi)核
webKit: u.indexOf('AppleWebKit') > -1, // 蘋果、谷歌內(nèi)核
gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHtml') === -1, // 火狐內(nèi)核
mobile: !!u.match(/AppleWebKit.*Mobile.*/), // 是否為移動(dòng)終端
ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), // ios終端
android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, // android終端或者uc瀏覽器
iPhone: u.indexOf('iPhone') > -1, // 是否為iPhone或者QQHD瀏覽器
iPad: u.indexOf('iPad') > -1, // 是否iPad
webApp: u.indexOf('Safari') === -1
}
}())
return versions.mobile || versions.iOS || versions.android || versions.iPhone || versions.iPad
}
我在使用時(shí)心里一直有疑問,一個(gè)移動(dòng)端,為什么要做那么多判斷呢?
目前我的 Chrome 瀏覽器:
看到這么一長(zhǎng)串字符串,我表示更懵逼, Mozilla不是firefox的廠商么?這是 Chrome 瀏覽器,又怎么會(huì)有 “Safari” 的關(guān)鍵字?那個(gè) “l(fā)ike Gecko” 又是什么鬼?
于是抱著這些疑問, 我打算好好深入了解一下瀏覽器檢測(cè)這部分,沒想到在學(xué)習(xí)過程中發(fā)現(xiàn)了挺有意思的事情,待我慢慢道來(lái),大家也聽個(gè)樂呵。
首先始于客戶端與服務(wù)器端通信,要求攜帶名稱與版本信息,于是服務(wù)器端與客戶端協(xié)定好在每個(gè)HTTP請(qǐng)求的頭部加上用戶代理字符串(userAgent),方便服務(wù)器端進(jìn)行檢測(cè),檢測(cè)通過之后再進(jìn)行后續(xù)操作。
早期的用戶代理字符串(userAgent)很簡(jiǎn)單, 就 "產(chǎn)品名稱/產(chǎn)品版本號(hào)",比如:"Mosaic/0.9"。93年之后,網(wǎng)景公司發(fā)布的Netscape Navigator 系列瀏覽器漸漸成為了當(dāng)時(shí)最受歡迎的瀏覽器,于是它擁有了規(guī)則制定權(quán),說從此以后我的用戶代理字符串就為:
這時(shí)肯定有人會(huì)問,"Mozilla" 是網(wǎng)景公司為 Netscape 瀏覽器定義的代號(hào),既然站在“食物鏈”頂端,那當(dāng)然得用自己的命名,這能理解??蔀樯吨钡浆F(xiàn)在,大部分主流瀏覽器的用戶代理字符串(userAgent),第一個(gè)名稱也是 “Mozilla” 呢?
這就是我即將要講的, 第一根攪屎棍——微軟。
96年,微軟推出了 IE3, 而當(dāng)時(shí) Netscape Navigator3 的市場(chǎng)占有率太高,微軟說,為了兼容 Netscape Navigator3, IE的用戶代理字符串從此就為:
看到?jīng)]有, 第一個(gè)名稱還是 “Mozilla”,這個(gè)誤導(dǎo)信息可以直接騙過服務(wù)器檢測(cè),而真正的 IE 版本放到后面去了。
大概意思就是初出茅廬的IE小同學(xué)怕自己知名度太低,萬(wàn)一服務(wù)端檢測(cè)不到自己,用戶流失了怎么辦?隔壁老大哥家大業(yè)大,那就干脆去蹭波流量吧。關(guān)鍵是蹭流量就蹭流量吧,還嘴硬說我這可是Mozilla/2.0哦,不是Mozilla/3.0哦,跟那個(gè)Netscape Navigator3 不能說沒有關(guān)系,只能說毫不相干。于是,IE成功地將自己偽裝成了 Netscape Navigator。
這在當(dāng)時(shí)來(lái)說是有爭(zhēng)議,但不得不說, 微軟這波操作相當(dāng)精準(zhǔn)。精準(zhǔn)到直到97年 IE4 發(fā)布時(shí),IE 的市場(chǎng)份額大幅增加,有了點(diǎn)話語(yǔ)權(quán),也不藏著掖著了, 就跟 Netscape 同時(shí)將版本升級(jí)到了 Mozilla/4.0, 之后就一直保持同步了。
看到 IE 這波操作,場(chǎng)外觀眾有點(diǎn)坐不住了,更多的瀏覽器廠商沿著IE的老路,蹭著 Netscape 的流量,在此基礎(chǔ)上依葫蘆畫瓢地設(shè)定自己的用戶代理字符串(userAgent)。直到 Gecko 渲染引擎 (firefox的核心) 開始大流行,用戶代理字符串(userAgent)基本已經(jīng)形成了一個(gè)比較標(biāo)準(zhǔn)格式,服務(wù)端檢測(cè)也能識(shí)別到 “Mozilla”、“Geoko” 等關(guān)鍵字,與之前字符串相比, 還增加了引擎、語(yǔ)言信息等等。
接下來(lái)我要說第二根攪屎棍——蘋果。
2003年,蘋果發(fā)布了 Safari, 它說,我的瀏覽器用戶代理字符串是這樣的:
Safari 用的渲染引擎是WebKit, 不是Gecko,它的核心是在渲染引擎KHTML基礎(chǔ)上進(jìn)行開發(fā)的,但是當(dāng)時(shí)大部分瀏覽器的用戶代理字符串(userAgent)都包含了 “Mozilla”、“Gecko”等關(guān)鍵字供服務(wù)器端檢測(cè)。
蘋果昂著臉,維持著表面的高傲,表示我的 WebKit 天下無(wú)敵、傲視群雄, 心里卻顫顫發(fā)抖,小心翼翼地在用戶代理字符串里加了個(gè)“l(fā)ike Gecko”,假裝我是Gecko ?!
這波操作可謂是又當(dāng)又立的典范!
我想可能心理陰影最大的要屬 Netscape 了,本來(lái) IE 來(lái)白嫖一波也就算了,你Safari 也要來(lái),而且本身蘋果的影響力就不容小覷,你再進(jìn)來(lái)插一腳,讓我以后怎么生存?但蘋果說:“Safari 與 Mozilla 兼容,不能讓網(wǎng)站以為用戶使用了不受支持的瀏覽器而把 Safari 排斥在外?!贝蟾乓馑际牵揖褪且祖?, 怎么樣?可以說是相當(dāng)不要臉了。
不過至少蘋果還有點(diǎn)藏著掖著, 而 Chrome 就有點(diǎn)不講武德,它說,成年人的世界不做選擇, 我想要的我都要:
Chrome 的渲染引擎是 Blink , Javascript引擎是 V8, 但它的用戶代理字符串(userAgent)中, 不僅包含了“Mozilla”、“l(fā)ike Gecko”,還包含了 “WebKit” 的引擎信息, 幾乎把能嫖的都嫖了, 只多了一個(gè) “Chrome” 名稱和版本號(hào),甚至都沒有一個(gè) “Blink” 關(guān)鍵字,節(jié)操碎了一地,簡(jiǎn)直觸目驚心,令人嘆為觀止。
到這里就不得不提一嘴高冷的Opera,直到Opera 8,用戶代理字符串(userAgent)一直都是 “Opera/Version (OS-or-CPU; Encryption [; language])”
Opera 一直給人一種世人皆醉我獨(dú)清、出淤泥而不染的氣概。到直到 Opera9 畫風(fēng)突然變了, 估計(jì)也是看到幾個(gè)大廠商各種騷操作,有點(diǎn)繃不住了,也跑去蹭流量。心態(tài)雖然崩但高冷人設(shè)不能崩,我就是不走尋常路,于是秀了一波玄學(xué)操作,它搞了兩套用戶代理字符串(userAgent):
場(chǎng)外觀眾表示有點(diǎn)看不懂, 蹭完 Firefox 又去蹭 IE,還得分開蹭,這哪是秀操作, 這可是秀智商??!縱觀瀏覽器發(fā)展的這幾十年,大概就是長(zhǎng)江后浪推前浪,后浪還沒把前浪踩死在沙灘上,后后浪又踩過來(lái)的一段歷史吧。就在這歷史的溪流中,用戶代理字符串(userAgent)也已經(jīng)形成了一個(gè)比較標(biāo)準(zhǔn)的格式。
目前,各個(gè)瀏覽器的用戶代理字符串(userAgent)始終包含著以下信息:
至于后來(lái)移動(dòng)端的 IOS 和 Andriod 基本的格式就成了:
這里的Mobile可能是 “iphone”、“ipad”、“BlackBerry”等等,Andriod設(shè)備的OS-or-CPU通常都是“Andriod”或“Linux”。所以,回到開頭的isMobile檢測(cè)函數(shù)內(nèi)部,一大堆的檢測(cè)判斷條件, 簡(jiǎn)直就是一粒粒歷史塵埃的堆疊。
同時(shí),本地Chrome瀏覽器輸出:
我也可以翻譯一下,大概意思就是,白嫖的Mozilla/5.0 + Macintosh平臺(tái) + Mac OS操作系統(tǒng) × 10_15_7版本白嫖的AppleWebKit引擎/537.36引擎版本號(hào) (KHTML內(nèi)核, like Gecko 假裝我是Gecko) Chrome瀏覽器/瀏覽器版本號(hào)99.0.4844.84 白嫖的Safari/Sarari版本號(hào)537.36。
本人表示很精彩, 一個(gè)用戶代理字符串猶如看了一場(chǎng)轟轟烈烈(巨不要臉)、你掙我奪(你蹭我蹭)的大戲!
??
02
第三方插件
接下來(lái), 為懶人推薦幾款用于瀏覽器檢測(cè)的省事的第三方插件。
1、如果只是檢測(cè)設(shè)備是否為手機(jī)端, 可以用 isMobile ,它支持在node端或?yàn)g覽器端使用。
地址:https://github.com/kaimallea/isMobile
2、如果要檢測(cè)設(shè)備的類型、版本、CPU等信息,可以用 UAParser ,它支持在node端或?yàn)g覽器端使用。
地址:https://github.com/faisalman/ua-parser-js
3、vue插件,vue-browser-detect-plugin
地址:https://github.com/ICJIA/vue-browser-detect-plugin
4、react插件,react-device-detect
地址:https://github.com/duskload/react-device-detect
5、在不同平臺(tái),要在Html中設(shè)置對(duì)應(yīng)平臺(tái)的CSS,可以用 current-device
地址:https://github.com/matthewhudson/current-device
需要注意的是, 第三方插件雖好用, 但也要注意安全問題哦,之前 UAParser 就被曝出被遭遇惡意投毒,所以只是簡(jiǎn)單的檢測(cè)盡量手寫。
??
03
移動(dòng)端與PC端分流
移動(dòng)端與PC端分流,可以用 nginx 來(lái)操作, nginx 可以通過 $http_user_agent 直接拿到用戶代理信息:
http {
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/pc; #pc端代碼目錄
if ($http_user_agent ~* '(Android|webOS|iPhone|iPod|BlackBerry)') {
root /usr/share/nginx/mobile; #移動(dòng)端代碼目錄
}
index index.html;
}
}
}
希望以上內(nèi)容能對(duì)有需要的人有所幫助
歡迎大家留言寫下自己希望了解的技術(shù)方向
歡迎大家一起探討交流
好了,這篇文章的內(nèi)容發(fā)貨聯(lián)盟就和大家分享到這里,如果大家網(wǎng)絡(luò)推廣引流創(chuàng)業(yè)感興趣,可以添加微信:80709525 備注:發(fā)貨聯(lián)盟引流學(xué)習(xí); 我拉你進(jìn)直播課程學(xué)習(xí)群,每周135晚上都是有實(shí)戰(zhàn)干貨的推廣引流技術(shù)課程免費(fèi)分享!