在 javascript 中模拟用户代理?

IT技术 javascript unit-testing user-agent
2021-01-21 00:39:49

我正在寻找一种以编程方式动态更改 navigator.userAgent 的方法。在我尝试获得自动化 javascript 单元测试器失败后,我放弃并尝试开始使用 fireunit。立即,我撞上了使用实际浏览器进行 javascript 测试的一堵墙。

具体来说,我需要更改 navigator.userAgent 来模拟几百个 userAgent 字符串,以确保对给定函数的正确检测和覆盖。navigator.userAgent 是只读的,所以我似乎卡住了!如何模拟 navigator.userAgent?用户代理切换器(插件)可以切换 FF 的用户代理,但是我可以在 javascript 中进行吗?

6个回答

尝试:

navigator.__defineGetter__('userAgent', function(){
    return 'foo' // customized user agent
});

navigator.userAgent; // 'foo'

在FF2和FF3中尝试过。

2021-03-18 00:39:49
这个解决方案可以用来设置 iframe 的用户代理吗?
2021-03-20 00:39:49
为我工作。(Windows 上的 IE)
2021-03-20 00:39:49
__defineGetter__ 已弃用,请defineProperty 改用。在下面检查我的答案。
2021-03-27 00:39:49
我最近创建了一个要点来使只读属性可写(您可以找到一个覆盖 navigator.userAgent 的示例)。它很丑,不推荐,但我将它用于单元测试以动态更改用户代理,所以要小心。要点:gist.github.com/moehlon/bed7dd6cb38fc55bd640
2021-04-04 00:39:49

添加到Crescent Fresh 的解决方案,重新定义navigator.userAgentgetter 在 Safari 5.0.5(在 Windows 7 和 Mac OS X 10.6.7 上)似乎不起作用。

需要创建一个从对象继承的新对象navigator并定义一个新的userAgentgetter来隐藏原来的userAgentgetter navigator

var __originalNavigator = navigator;
navigator = new Object();
navigator.__proto__ = __originalNavigator;
navigator.__defineGetter__('userAgent', function () { return 'Custom'; });
这也适用于 phantomjs ......需要新的对象。我猜它是一个 webkit 的东西。
2021-03-22 00:39:49
我无法覆盖 window.navigator 对象,因此您的解决方案对我不起作用。'Crescent Fresh'的那个。
2021-04-06 00:39:49
不适用于 Safari 版本 12.1.2 (14607.3.9)。在线 Javascript 错误navigator.__proto__ = __originalNavigator;,它说:cyclic __proto__ value或这样。删除该行使用户代理“在本地工作”,这意味着navigator.userAgent将返回您设置的内容,但对于 XMLHttpRequest 调用,它将只使用默认的 UA。
2021-04-13 00:39:49

以下解决方案适用于 Chrome、Firefox、Safari、IE9+ 以及 iframe:

function setUserAgent(window, userAgent) {
    if (window.navigator.userAgent != userAgent) {
        var userAgentProp = { get: function () { return userAgent; } };
        try {
            Object.defineProperty(window.navigator, 'userAgent', userAgentProp);
        } catch (e) {
            window.navigator = Object.create(navigator, {
                userAgent: userAgentProp
            });
        }
    }
}

例子:

setUserAgent(window, 'new user agent');
setUserAgent(document.querySelector('iframe').contentWindow, 'new user agent');
我在 Safari 8 上进行了测试,但它似乎不起作用。我使用 console.log(navigator.userAgent) 并且控制台记录默认的用户代理字符串。
2021-03-15 00:39:49
@AeroWindwalker 我刚刚再次在 Safari 8 中对其进行了测试,并且可以正常工作。
2021-03-15 00:39:49
是的,我意识到脚本有效。只是 iframe 在脚本应用新的用户代理之前将默认用户代理发送到服务器。
2021-03-15 00:39:49
但是,我认为可能是在脚本更改用户代理之前我有 console.log。
2021-03-19 00:39:49
@AeroWang 你是如何解决这个问题的? the iframe sent the default user agent to the server before the script applies a new user agent to it.
2021-04-12 00:39:49

对于这里的人,因为他们需要在单元测试中更改 userAgent 值,Tyler Long 的解决方案有效,但是如果您想恢复初始 userAgent 或多次更改它,您可能需要将该属性设置为可配置:

function setUserAgent(userAgent) {
    Object.defineProperty(navigator, "userAgent", { 
        get: function () { 
            return userAgent; // customized user agent
        },
        configurable: true
    });
}

// Now in your setup phase:
// Keep the initial value
var initialUserAgent = navigator.userAgent;
setUserAgent('foo');

// In your tearDown:
// Restore the initial value
setUserAgent(initialUserAgent);

否则,您可能会遇到TypeError: Cannot redefine property错误。在 Chrome Headless 上对我有用。

这现在在 Windows Google Chrome 版本 78.0.3904.108(官方版本)(64 位)中对我不起作用
2021-03-22 00:39:49
经过反复试验,我得出了同样的结论,希望我先阅读这个答案。
2021-03-23 00:39:49
谢谢,像魅力一样工作 const setUserAgent = (userAgent: 'Chrome' | 'Android') => { Object.defineProperty(navigator, 'userAgent', { get: () => userAgent, configurable: true, }); };
2021-04-03 00:39:49

使用 Object.defineProperty 应该会添加更多浏览器:

if (navigator.__defineGetter__) {
    navigator.__defineGetter__("userAgent", function () { 
        return "ua"; 
    });
} else if (Object.defineProperty) { 
    Object.defineProperty(navigator, "userAgent", { 
        get: function () { 
            return "ua";
        }
    });
}

此代码应该在Firefox 1.5+Chrome 6+Opera 10.5+IE9+ 中工作(并经过测试)不幸的是,任何平台上的 Safari 都不允许更改 userAgent。

编辑:Safari 不允许更改 userAgent,但可以替换整个导航器对象,如上面的另一个解决方案中所指出的。

不幸的是,我不知道任何。
2021-03-15 00:39:49
嘿Bundyo,有没有办法在IE8 中做同样的事情?
2021-03-27 00:39:49