FirefoxBar / HeaderEditor

Manage browser's requests, include modify the request headers and response headers, redirect requests, cancel requests

Home Page:https://he.firefoxcn.net/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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

runningcheese opened this issue · comments

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

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

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

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

iShot2022-09-15 16 05 56

代码执行时机不对

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

使用url参数传递标识也行

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

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

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

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

@jingjingxyk

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

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

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

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

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

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


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

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

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

@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

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