Skip to content

[Question] 能否通过检测窗口大小来设置浏览器 UA? #216

Closed

Description

@runningcheese

能否通过检测窗口大小来设置浏览器 UA?

比如 https://fm.douban.com,

当浏览器窗口比较大时,使用浏览器本身的 UA 来访问。
而当浏览器窗口比较小时,使用 iPhone 的 UA 来访问。

我尝试过用自定义函数设置,但没能达到理想的效果,请问我是那里出问题了吗?谢谢~

iShot2022-09-15 16 05 56

Activity

  1. jingjingxyk commented on Nov 24, 2022

    @jingjingxyk

    代码执行时机不对

    请看执行顺序哈 (自定义函数中,if 判断条件为真的代码,不会被执行到)

    https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webRequest

    判断条件不正确哈,因为此时环境获取不到宽、高

    解决办法: 窗口大小改变时设置cookie 标志位

    发起请求前,判断cookie里是否有传递的标志位,依据cookie标志位,决定是否需要修改UA

  2. runningcheese commented on Dec 7, 2022

    @runningcheese
    Author

    @jingjingxyk 那具体应该怎么写呢,这个还真没明白。

  3. jingjingxyk commented on Dec 7, 2022

    @jingjingxyk

    @jingjingxyk 那具体应该怎么写呢,这个还真没明白。

    窗口大小变化时候,用js自定义cookie 键值对

    浏览器请求时,请求头里自带cookie,你就能获取到你设置的值

    上述代码的判断条件改成 判断自定义cookie键值

  4. jingjingxyk commented on Dec 7, 2022

    @jingjingxyk

    分成2部分,第1部分是设置cookie 值,第2部分是判断cookie值

    这是使用cookie 传递自定义参数

    根据窗口大小设置cookie标识

    这部分代码,由扩展的 content_scripts 执行

    function setCookie(name, value, second, path, domain) {
        var exp = new Date();
        exp.setTime(exp.getTime() + second * 1000);
        document.cookie =
            name +
            "=" +
            encodeURIComponent(value) +
            ";expires=" +
            exp.toGMTString() +
            ";path=" + path +
            ";domain=" +
            domain +
            ";SameSite=None;Secure";
    }
    
    
    function set_flag() {
        let second = 365 * 24 * 60 * 60
        if (document.documentElement.clientWidth <= 480) {
            setCookie('custom_window_ua_flag', 1, second, '/', document.domain)
        } else {
            setCookie('custom_window_ua_flag', 0, second, '/', document.domain)
        }
    }
    
    
    set_flag()
    
    window.onresize = function () {
        set_flag()
    }
    

    使用cookie标识 也就是你上述的代码修改版

    这部分代码由 chrome.webRequest.onBeforeSendHeaders.addListener 函数执行

    chrome.webRequest.onBeforeSendHeaders.addListener(
        (details) => {
            console.log(details)
            let urlObj = new URL(details.url);
            console.log(urlObj)
    
            let ua_index = 0;
            let referer_index = 0;
            let cookie_index = 0;
    
            for (const [index, header] of details.requestHeaders.entries()) {
                if (header.name.toLowerCase() === "user-agent") {
                    ua_index = index;
                }
                if (header.name.toLowerCase() === "referer") {
                    referer_index = index;
                }
                if (header.name.toLowerCase() === "cookie") {
                    cookie_index = index;
                }
            }
    
            for (const header of details.requestHeaders) {
                console.log(header.name, '=', header.value)
    
                if (header.name.toLowerCase() === "cookie") {
                    let custom_window_ua_flag = 0
                    let reg = new RegExp("(^| )custom_window_ua_flag=([^;]*)(;|$)");
                    let arr = header.value.match(reg)
                    console.log(arr)
                    if (arr && arr.length > 1) {
                        custom_window_ua_flag = decodeURIComponent(arr[2]);
                        console.log(custom_window_ua_flag)
                        if (custom_window_ua_flag == 1) {
                            details.requestHeaders[ua_index]['value'] =
                                "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1";
    
                        }
                    }
                }
    
                if (header.name.toLowerCase() === "referer" && (details.type === "sub_frame" ))  {
                    //通过referer传递参数,编写你需要的逻辑
                    let referer=header.value
                    let urlObj = new URL(referer);
                    console.log(urlObj)
                    let custom_parameter=urlObj.searchParams.get(' custom_parameter')
    
                    if (details.type === "sub_frame") {
                        details.requestHeaders[ua_index]['value'] =
                            "Mozilla/5.0 (Linux; Android 11; SM-A505F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.79 Mobile Safari/537.36";
    
                    }
                }
    
            }
            return {requestHeaders: details.requestHeaders};
        },
        {
            urls: [
                "*://*.douban.com/*",
            ],
        },
        ["blocking", "requestHeaders", 'extraHeaders']
    );
    
    

    都写到这个份上了,自己新建一个扩展就完事了

  5. jingjingxyk commented on Dec 7, 2022

    @jingjingxyk

    下面是依照上面的要求,一个完整的扩展

    manifest.json 文件

    {
      "name": "修改UA",
      "version": "0.0.1",
      "manifest_version": 2,
      "description": "修改UA",
      "content_scripts": [
        {
          "matches": ["https://fm.douban.com/*"],
          "js": ["content-script.js"]
        }
      ],
      "background": {
        "scripts": ["background.js"]
      },
      "incognito": "spanning",
      "permissions": ["webRequest", "webRequestBlocking", "<all_urls>"]
    
    }
    
    

    content-script.js

     function setCookie(name, value, second, path, domain) {
        var exp = new Date();
        exp.setTime(exp.getTime() + second * 1000);
        document.cookie =
            name +
            "=" +
            encodeURIComponent(value) +
            ";expires=" +
            exp.toGMTString() +
            ";path=" + path +
            ";domain=" +
            domain +
            ";SameSite=None;Secure";
    }
    
    
    function set_flag() {
        let second = 365 * 24 * 60 * 60
        if (document.documentElement.clientWidth <= 480) {
            setCookie('custom_window_ua_flag', 1, second, '/', document.domain)
        } else {
            setCookie('custom_window_ua_flag', 0, second, '/', document.domain)
        }
    }
    
    
    set_flag()
    
    window.onresize = function () {
        set_flag()
    }

    background.js

    chrome.webRequest.onBeforeSendHeaders.addListener(
        (details) => {
            console.log(details)
            let urlObj = new URL(details.url);
            console.log(urlObj)
    
            let ua_index = 0;
            let referer_index = 0;
            let cookie_index = 0;
    
            for (const [index, header] of details.requestHeaders.entries()) {
                if (header.name.toLowerCase() === "user-agent") {
                    ua_index = index;
                }
                if (header.name.toLowerCase() === "referer") {
                    referer_index = index;
                }
                if (header.name.toLowerCase() === "cookie") {
                    cookie_index = index;
                }
            }
    
            for (const header of details.requestHeaders) {
                console.log(header.name, '=', header.value)
    
                if (header.name.toLowerCase() === "cookie") {
                    let custom_window_ua_flag = 0
                    let reg = new RegExp("(^| )custom_window_ua_flag=([^;]*)(;|$)");
                    let arr = header.value.match(reg)
                    console.log(arr)
                    if (arr && arr.length > 1) {
                        custom_window_ua_flag = decodeURIComponent(arr[2]);
                        console.log(custom_window_ua_flag)
                        if (custom_window_ua_flag == 1) {
                            details.requestHeaders[ua_index]['value'] =
                                "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1";
    
                        }
                    }
                }
    
                if (header.name.toLowerCase() === "referer" && (details.type === "sub_frame" ))  {
                    //通过referer传递参数,编写你需要的逻辑
                    let referer=header.value
                    let urlObj = new URL(referer);
                    console.log(urlObj)
                    let custom_parameter=urlObj.searchParams.get(' custom_parameter')
    
                    if (details.type === "sub_frame") {
                        details.requestHeaders[ua_index]['value'] =
                            "Mozilla/5.0 (Linux; Android 11; SM-A505F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.79 Mobile Safari/537.36";
    
                    }
                }
    
            }
            return {requestHeaders: details.requestHeaders};
        },
        {
            urls: [
                "*://*.douban.com/*",
            ],
        },
        ["blocking", "requestHeaders", 'extraHeaders']
    );
    
  6. jingjingxyk commented on Dec 7, 2022

    @jingjingxyk

    上述办法是通过cookie 传递标识,也可以不使用cookie

    使用url参数传递标识也行

  7. runningcheese commented on Dec 7, 2022

    @runningcheese
    Author

    @jingjingxyk 大佬厉害!!!

    另外,我还有一点疑问。

    if (detail.type === "sub_frame") {
    for (const a in val) {
        if (val[a].name.toLowerCase() === 'user-agent') {
            val[a].value += 'Mozilla/5.0 (Linux; Android 11; SM-A505F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.79 Mobile Safari/537.36';   break;  }}}
    

    上面的代码是指定 iframe 框架的,
    有没有办法指定某个具体 ID 的 iframe 呢?
    我试过用 document.querySelector 来指定,但没成功,请还指教,也是用 Header Editor 的方案。

  8. jingjingxyk commented on Dec 7, 2022

    @jingjingxyk

    因为扩展执行环境和网页执行环境,是两个独立的环境。 获取不到哈。

    你没发现,按照上述的做法,你自己也写了一个,自用版的Header Editor

    但是可以换种思路,你可以借助 referer,实现你想要的功能

  9. runningcheese commented on Dec 7, 2022

    @runningcheese
    Author

    @jingjingxyk

    var iframe = document.querySelector("iframe");
    if(iframe .getAttribute("id") == "frame") {
    xxx
    }
    

    这样指定也不行吗?好奇。

    另外,我把您说的“2部分”,添加到 header editor 里了,但好像不起作用。

  10. sylingd commented on Dec 7, 2022

    @sylingd
    Member

    解释一下原因:重定向相关功能,包括自定义函数,运行于background page,你可以把它视为一个类似ServiceWorker的存在。

    它没有完整的DOM能力(目前有,但本身与浏览器的“窗口”不在一个地方,且未来会移除),自然是无法“检测”窗口大小的。

    所以,这也解释了你一开始用媒体查询为什么不起作用,因为它们根本不在一个地方运行。你“查询”出来的是一个运行在后台的window大小——实际我也不知道,它到底有多高、多宽。


    楼上给的建议是结合content-script进行,这是一种可行的方式,因为content-script实际运行于网页中。另一个思路是,通过browser.tabs相关API来获取具体的窗口。但这两种方式,仅仅通过HE是无法实现的。

    1. 第一种方式,需要增加content-script,而HE基于background运行,本身没有该功能。
    2. 第二种方式,为了能在合适的时机获取大小,你还需要增加一些额外的事件监听。这在HE的自定义函数中是不可取的做法。

    综合而言,如果你真有相关诉求,考虑单独写一个插件进行。

  11. jingjingxyk commented on Dec 7, 2022

    @jingjingxyk

    @runningcheese
    看楼上的回复,说的很清楚!

    你只要自己解决传递的参数,就能实现你要得效果

    自定义函数可以修改成这样,通过url传参的方式,传递 custom_window_ua_flag=1 ,进而达成修改UA的目录

    {
    
      let ua_index = 0;
      let referer_index = 0;
      let cookie_index = 0;
    
      for (const [index, header] of detail.requestHeaders.entries()) {
        if (header.name.toLowerCase() === "user-agent") {
          ua_index = index;
        }
        if (header.name.toLowerCase() === "referer") {
          referer_index = index;
        }
        if (header.name.toLowerCase() === "cookie") {
          cookie_index = index;
        }
      }
    
      let urlObj = new URL(detail.url);
      if ( urlObj.searchParams.get('custom_window_ua_flag') == 1 ) {
        detail.requestHeaders[ua_index]['value'] = 'Mozilla/5.0 (Linux; Android 11; SM-A505F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.79 Mobile Safari/537.36';
      }
    
    }

    测试地址: https://fm.douban.com/?custom_window_ua_flag=1

    参考文档 https://he.firefoxcn.net/zh-CN/custom-function.html#%E7%BB%BC%E8%BF%B0

  12. runningcheese commented on Dec 7, 2022

    @runningcheese
    Author

    感谢两位的耐心回复,感谢 🤝

  13. jingjingxyk commented on Dec 29, 2022

    @jingjingxyk
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions