HeaderEditor
HeaderEditor copied to clipboard
[Question] 能否通过检测窗口大小来设置浏览器 UA?
能否通过检测窗口大小来设置浏览器 UA?
比如 https://fm.douban.com,
当浏览器窗口比较大时,使用浏览器本身的 UA 来访问。 而当浏览器窗口比较小时,使用 iPhone 的 UA 来访问。
我尝试过用自定义函数设置,但没能达到理想的效果,请问我是那里出问题了吗?谢谢~

代码执行时机不对
请看执行顺序哈 (自定义函数中,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是无法实现的。
- 第一种方式,需要增加content-script,而HE基于background运行,本身没有该功能。
- 第二种方式,为了能在合适的时机获取大小,你还需要增加一些额外的事件监听。这在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
感谢两位的耐心回复,感谢 🤝
@runningcheese v3版本的例子也写好了 https://github.com/jingjingxyk/extension-v3-test/tree/main/example/v3