https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name
"Note: The User-Agent header is no longer forbidden, as per spec — see forbidden header name list (this was implemented in Firefox 43) — it can now be set in a Fetch Headers object, or with the setRequestHeader() method of XMLHttpRequest. However, Chrome will silently drop the header from Fetch requests (see Chromium bug 571722 )."
User-Agent header 不再被禁止更改,现在可以设置在 Fetch 的 Headers 对象中,或者通过 XMLHttpRequest 的 setRequestHeader() 方法设置。但是,Chrome 会不做提示地从 Fetch 请求中丢弃这个Header(请参阅 Chromium bug 571722 )
看了下这个bug 从 2015年就有了, 而且仍然是open状态,2023.7月亲自试了下,直接在fetch request里面设置"User-agent": "Custom User Agent"
,发现确实chrome仍然有这个bug, Firefox 和Safari 都可以成功修改User-agent Header。
测试版本:
Google Chrome Version 114.0.5735.198 (Official Build) (arm64)
Firefox 113.0.2
Safari Version 16.5 (18615.2.9.11.4)
1 2 3 fetch("https://httpbin.org/user-agent" , (credentials: "include" , method : "GET', headers: / " User-agent": " Custom User Agent" Promise ([PromiseStatus]]: " pending", ((PromiseValue]]: undefined}
window.navigator
返回一个Navigator
对象的引用, 用于请求运行当前代码的应用程序的相关信息.
Navigator
对象包含了一些关于浏览器的信息, 具体可以查阅Navigator MDN
1 2 3 const userAgent = window .navigator.userAgent;
JavaScript修改UserAgent string
navigator.userAgent属性是只读属性,不建议修改 。
但是仍然可以通过override navigator的get方法来修改, 参考代码Override user agent on all browsers 。
需要注意的是这种修改方法:
不会修改request里面的User-agent
Header
只是修改了navigator.userAgent (navigator的get方法)得到的userAgent string
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 function setUserAgent (window, customUserAgent ) { const newUserAgent = `${navigator.userAgent} ${customUserAgent} ` ; if (navigator.__defineGetter__) { navigator.__defineGetter__('userAgent' , function ( ) { return newUserAgent; }); } else if (Object .defineProperty) { Object .defineProperty(navigator, 'userAgent' , { get : function () { return newUserAgent; }, }); } if (window .navigator.userAgent.indexOf(customUserAgent) < 0 ) { const userAgentProp = { get : function () { return newUserAgent; }, }; try { Object .defineProperty(window .navigator, 'userAgent' , userAgentProp); } catch (e) { window .navigator = Object .create(navigator, { userAgent: userAgentProp, }); } } } setUserAgent(window , 'CustomUserAgent/1.0' );
改进版本,抽取一些函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 function getNewUserAgent (userAgent, customUserAgent ) { return userAgent.indexOf(customUserAgent) < 0 ? `${userAgent} ${customUserAgent} ` : userAgent; } function getNewUserAgentProp (userAgent, customUserAgent ) { return { get : function () { return getNewUserAgent(userAgent, customUserAgent); }, }; } function setUserAgent2 (window, customUserAgent ) { const userAgent = navigator.userAgent; const winUserAgent = window .navigator.userAgent; if (navigator.__defineGetter__) { navigator.__defineGetter__('userAgent' , function ( ) { return getNewUserAgent(userAgent, customUserAgent); }); } else if (Object .defineProperty) { Object .defineProperty(navigator, 'userAgent' , getNewUserAgentProp(userAgent, customUserAgent)); } if (winUserAgent.indexOf(customUserAgent) < 0 ) { try { Object .defineProperty( window .navigator, 'userAgent' , getNewUserAgentProp(winUserAgent, customUserAgent) ); } catch (e) { window .navigator = Object .create(navigator, { userAgent: getNewUserAgentProp(navigator.userAgent, customUserAgent), }); } } if (navigator.userAgentData) { navigator.userAgentData.getHighEntropyValues(['uaFull' ]).then(function (uaData ) { uaData.uaFull = getNewUserAgent(uaData.uaFull, customUserAgent); navigator.userAgentData.setHighEntropyValues(uaData); }); } } setUserAgent2(window , 'CustomUserAgent/1.0' );
Chrome中修改一下userAgent:
首先打开开发者工具(F12)
点开关闭箭头左侧更多选项, 选择More tools, 然后选择Network conditions
在开发者工具下方会多出来一个Network conditions菜单栏, 这里有User agent配置, 取消勾选Use browser default, 然后选择一些其他的选项或者自己输入一些内容.
刷新页面后, window.navigator
, 和网络请求头中的User Agent都会变成了刚才修改的内容
利用userAgent检测浏览器
userAgent string直接判断
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 const isIE = !!document .all, docMode = document .documentMode, ua = navigator.userAgent, isIE6 = false , isIE7 = false , isIE8 = false , isIE9 = false , isIE10 = false , isIE11 = !isIE && 'ActiveXObject' in window , isDXIE = false ; isIE = isIE || isIE11; if (isIE) { if (isEdgeModeEnabled) { isIE6 = !!ua.match(/MSIE 6/ ); isIE7 = ((!!ua.match(/MSIE 7/ ) && !docMode) || docMode === 7 ); isIE8 = (docMode === 8 ); isIE9 = (docMode === 9 ); isIE10 = (docMode === 10 ); isDXIE = (!docMode || docMode <= 9 ); } else { isIE6 = !!ua.match(/MSIE 6/ ); isIE7 = !!ua.match(/MSIE 7/ ); isIE8 = !!ua.match(/MSIE 8/ ); isIE9 = !!ua.match(/MSIE 9/ ); isIE10 = !!ua.match(/MSIE 10/ ); isDXIE = !isIE10; } } const isFireFox = !isIE && !!ua.match(/Firefox/ ), isAndroid = !!ua.match(/Android/ ), isIPad = !!ua.match(/iPad/ ), isIPhone = !!ua.match(/iPhone/ ), isIOSTouchWithDesktopWebsite = !!ua.match(/Macintosh/ ) && 'ontouchend' in document , tch = !!document .createTouch || isAndroid, isPlayBook = !!ua.match(/PlayBook/ ), isWinPhone = !!ua.match(/Windows Phone/ ), isIEW3C = !isIE && !!ua.match(/Trident.*rv/ ), CSS3_PREFIX = isFireFox ? '-moz-' : (isIE || isIEW3C) ? '' : '-webkit-' , CSS3_TRANSFORM_PREFIX = isFireFox ? 'Moz' : (isIE10 || isIEW3C) ? '' : isIE ? 'ms' : 'webkit' , CSS3_T_INITIAL = ((isIE10 || isIEW3C) ? 't' : 'T' ), CSS3_TRANSITION = CSS3_TRANSFORM_PREFIX + CSS3_T_INITIAL + 'ransition' ;
包装了一些常用方法,使用起来更方便,github 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 import UAParser from 'ua-parser-js' ;let uaParser = new UAParser();const osName = uaParser.getOS().name;const deviceType = uaParser.getDevice().type;export function getBrowserVersion ( ) { return uaParser.getBrowser().version; } export function isSafari ( ) { return uaParser.getBrowser().name === 'Safari' || uaParser.getBrowser().name === 'Mobile Safari' ; } export function isFirefox ( ) { return uaParser.getBrowser().name === 'Firefox' ; } export function isChrome ( ) { return uaParser.getBrowser().name === 'Chrome' || uaParser.getBrowser().name === 'Chrome WebView' ; } export function isIE ( ) { return uaParser.getBrowser().name === 'IE' || uaParser.getBrowser().name === 'IE Mobile' ; } export function isEdge ( ) { return uaParser.getBrowser().name === 'Edge' ; } export function isDesktop ( ) { return ((isMacOS() || isWindows()) && window .navigator.maxTouchPoints <= 1 ) || isLinux(); } export function isIpadIOS13AndAbove ( ) { return isMacOS() && window .navigator.maxTouchPoints > 1 ; } export function isWindowsTablets ( ) { return isWindows() && window .navigator.maxTouchPoints > 1 ; } export function isLinux ( ) { return osName === 'Linux' ; } export function isMacOS ( ) { return osName === 'Mac OS' ; } export function isWindows ( ) { return osName === 'Windows' ; } export function isIPad ( ) { return osName === 'iOS' && deviceType === 'tablet' ; } export function isIPhone ( ) { return osName === 'iOS' && deviceType === 'mobile' ; } export function isIOS ( ) { return osName === 'iOS' ; } export function isAndroid ( ) { return osName === 'Android' ; } export function isAndroidPhone ( ) { return osName === 'Android' && deviceType === 'mobile' ; } export function isMobile ( ) { return deviceType === 'mobile' ; } export function isTouchable ( ) { const maxTouchPoints = navigator.maxTouchPoints || navigator.msMaxTouchPoints; return ( 'ontouchstart' in window || maxTouchPoints > 0 || (window .matchMedia && matchMedia('(any-pointer: coarse)' ).matches) ); } export function isSurface ( ) { return osName === 'Windows' && isTouchable(); } export function isTablet ( ) { return deviceType === 'tablet' || isSurface(); } export function isMobileOrTabletDevice ( ) { return isTablet() || isMobile(); }
参考文章
本文由
Yuankun Li 创作和发表,采用
BY -
NC -
SA 国际许可协议进行许可,转载请注明作者及出处。