Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
runningcheese opened this issue Sep 15, 2022 · 13 comments
Open

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

runningcheese opened this issue Sep 15, 2022 · 13 comments

Comments

@runningcheese
Copy link

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

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

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

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

iShot2022-09-15 16 05 56

@jingjingxyk
Copy link

jingjingxyk commented Nov 24, 2022

代码执行时机不对

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

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

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

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

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

@runningcheese
Copy link
Author

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

@jingjingxyk
Copy link

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

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

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

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

@jingjingxyk
Copy link

jingjingxyk commented Dec 7, 2022

分成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']
);

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

@jingjingxyk
Copy link

jingjingxyk commented Dec 7, 2022

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

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']
);

@jingjingxyk
Copy link

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

使用url参数传递标识也行

@runningcheese
Copy link
Author

runningcheese commented Dec 7, 2022

@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 的方案。

@jingjingxyk
Copy link

jingjingxyk commented Dec 7, 2022

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

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

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

@runningcheese
Copy link
Author

@jingjingxyk

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

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

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

@sylingd
Copy link
Member

sylingd commented Dec 7, 2022

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

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

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


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

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

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

@jingjingxyk
Copy link

jingjingxyk commented Dec 7, 2022

@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

@runningcheese
Copy link
Author

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

@jingjingxyk
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants