Electron 提供的 webRequest API,允许开发者对网络进行过滤和监听,并且可以修改 header 字段甚至请求地址,功能非常强大,它的类结构如下:
不过需要注意,该模块只能在主进程中使用,接下来为大家介绍 webRequest 三个非常典型的使用场景:
一 绕过跨域限制
使用 Electron 加载第三方网站的时候,默认行为和 Chrome 是一致的,都会受到同源策略的影响。
-
使用nodejs搭建测试服务器,启动3000和4000端口。此时在控制台请求 3000 端口上的服务,会发现典型的跨域报错,果不其然被 cors 策略拒绝了:
-
没有配置前,在渲染进程中的控制台调用接口
fetch('http://localhost:3000').then(it=>it.json()).then(it=>console.log(it))
- 报错
- 主进程中设置请求转发
// 绕过跨域限制
const mainWindow = CoreWindow.getMainWindow();
mainWindow.webContents.session.webRequest.onHeadersReceived(
{
urls: ["http://localhost:*/*"],
},
(details, callback) => {
const { responseHeaders } = details;
responseHeaders["Access-Control-Allow-Origin"] = ["*"];
callback({ responseHeaders });
}
);
请求转发
- 通过 webRequest API,可以将发到接口 A 的请求转发到接口 B。
- 为了验证这个能力,我们写了一个 http 服务,同时监听 3000 和 4000 端口,并响应 JSON 数据,里面包含了 port 字段表示当前请求到了哪个端口。先上效果图。
// 设置网络代理
setProxy() {
if (!this.setProxyFlag) {
const mainWindow = CoreWindow.getMainWindow();
const sessionItem = mainWindow.webContents.session;
// Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) ywxd-ee/1.0.1 Chrome/106.0.5249.199 Electron/21.4.4 Safari/537.36
const UserAgent = sessionItem.getUserAgent();
xdLogInfo(`[basehttp:setProxy] UserAgent = ${UserAgent}`);
// 自定义 UA
const filter = {
urls: ["http://localhost:3000/*"],
};
// 自定义 UA
// 有些接口为了过滤非法请求,会首先校验 UserAgent,正常的浏览器是无法伪造 UA 的,
//不过在 Electron 里面可以很容易做到,webRequest 模块提供的 onBeforeSendHeaders 方法能够对域名进行过滤,
// 拦截即将发出去的请求头,修改之后再真正的发出去。
mainWindow.webContents.session.webRequest.onBeforeSendHeaders(
// filter,
{
urls: ["http://localhost:3000/*"],
},
(details, callback) => {
details.requestHeaders["User-Agent"] = "MyAwesomeAgent";
callback({ requestHeaders: details.requestHeaders });
}
);
// 请求转发,通过 webRequest API,可以将发到接口 3000 的请求转发到接口 4000。
mainWindow.webContents.session.webRequest.onBeforeRequest(
// filter,
{
urls: ["http://localhost:3000/*"],
},
(details, callback) => {
// callback({ redirectURL: "http://localhost:4000" });
// 使用正则表达式提取原请求的 path 和 query
const url = new URL(details.url);
const pathAndQuery = url.pathname + url.search;
// 构建新的 URL,替换 IP 和端口
const redirectURL = `http://localhost:4000${pathAndQuery}`;
console.log(`[basehttp:setProxy] redirectURL = ${redirectURL}`);
callback({ redirectURL });
}
);
// 绕过跨域限制
mainWindow.webContents.session.webRequest.onHeadersReceived(
{
urls: ["http://localhost:*/*"],
},
(details, callback) => {
const { responseHeaders } = details;
responseHeaders["Access-Control-Allow-Origin"] = ["*"];
callback({ responseHeaders });
}
);
}
}
- 自定义的nodejs 服务核心代码
- nodejs服务器代码具体方法请参考上一篇博文# Electron 自动更新,绕过 latest.yml 使用自定义接口中【### 自定义服务器接口的具体步骤】。
// server.js
const express = require("express");
const URL = require('url')
let count = 1;
// 封装成一个方法
function startServer(port = 3000) {
const app = express();
// 定义一个 GET 路由
app.get("/", (req, res) => {
console.log(`Server is running on http://localhost:${port}`);
const { url, method, headers } = req
const { query, pathname } = URL.parse(url, true)
const sendData = { method, pathname, query, headers, port };
count ++;
console.log(` &&&&&&&&&&& ****************** `);
console.log(`originalUrl = ${req.originalUrl}`);
console.log(`query = ${JSON.stringify(req.query)}`);
console.log(` count=${count}, ${port} port收到请求 ----- ${JSON.stringify(sendData)}`);
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify(sendData))
});
// 调测接口转发请求
app.get("/xd/:platform", (req, res, next) => {
const { url, method, headers } = req
const { query, pathname } = URL.parse(url, true)
const sendData = { method, pathname, query, headers, port };
count ++;
console.log(` ****************** `);
console.log(` count=${count}, ${port} port收到请求 -----`);
console.log(` ${port} port收到请求 ----- ${JSON.stringify(sendData)}`);
let { platform } = req.params;
console.log(`originalUrl = ${req.originalUrl}`);
console.log(`query = ${JSON.stringify(req.query)}`);
console.log(`platform = ${platform}`);
let resinfo = null;
resinfo = { code: 0, msg: "成功",
"path": "xd-mac-1.0.1-arm64.zip",
"releaseDate": "2024-05-07T10:46:31.141Z",
"sha512": "vFlUCW+SdhNvyvY42TIVYwn8FWkkMd9pxvbrovZ0mZREJk+dinrNo13VhbqV7drMu3suGg7LOSZ7XAwdK633dw==",
"version": "1.0.1"
};
res.send(resinfo);
});
// 启动服务器
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});
}
// 导出方法
module.exports = {
startServer,
};
// index.js
// 启动服务器
startServer(3000);
startServer(4000);
参考
作者:乔珂力
链接:juejin.cn/post/720810…
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。