You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Electron中interceptBufferProtocol弃用后,如何用protocol.handle拦截HTTP/HTTPS?

问题

我在Electron应用里要做一个验证码收集弹窗,找了个旧仓库的代码,原代码用的是旧版Electron的interceptBufferProtocol,现在新版Electron要用protocol.handle替换,但我改完后没法实现HTTP协议拦截。下面是原函数和我改写后的函数,求正确的更新方式。

原函数

function SetupIntercept() {
    protocol.interceptBufferProtocol('http', (req, callback) => {
        if(req.url == 'https://www.google.com/recaptcha/api2/demo') {
            fs.readFile(__dirname + '/captcha.html', 'utf8', function(err, html){
                callback({mimeType: 'text/html', data: Buffer.from(html)});
            });
        }else{
            const request = net.request(req)
            request.on('response', res => {
                const chunks = []

                res.on('data', chunk => {
                    chunks.push(Buffer.from(chunk))
                })

                res.on('end', async () => {
                    const file = Buffer.concat(chunks)
                    callback(file)
                })
            })

            if (req.uploadData) {
                req.uploadData.forEach(part => {
                    if (part.bytes) {
                        request.write(part.bytes)
                    } else if (part.file) {
                        request.write(readFileSync(part.file))
                    }
                })
            }

            request.end()
        }
    })
};

改写后的函数

function SetupIntercept() {
    protocol.handle('http', async (req) => {
        if (req.url === 'http://supremenewyork.com/') {
            try {
                const html = await fs.promises.readFile(__dirname + '/captcha.html', 'utf8');
                return {
                    mimeType: 'text/html',
                    data: Buffer.from(html),
                };
            } catch (err) {
                console.error('Error reading captcha.html:', err);
                return {
                    mimeType: 'text/plain',
                    data: Buffer.from('Error loading page'),
                };
            }
        } else {
            return new Promise((resolve, reject) => {
                const request = net.request(req);
                request.on('response', (res) => {
                    const chunks = [];
    
                    res.on('data', (chunk) => {
                    chunks.push(Buffer.from(chunk));
                    });
    
                    res.on('end', () => {
                    const file = Buffer.concat(chunks);
                    resolve({ data: file });
                    });
    
                    res.on('error', (error) => {
                    console.error('Error in response:', error);
                    reject({
                        mimeType: 'text/plain',
                        data: Buffer.from('Error loading page'),
                    });
                    });
                });
    
                if (req.uploadData) {
                    req.uploadData.forEach((part) => {
                    if (part.bytes) {
                        request.write(part.bytes);
                    } else if (part.file) {
                        request.write(readFileSync(part.file));
                    }
                    });
                }
    
                request.end();
            });
        }
    });
}
解决方案

你的改写存在几个关键问题,导致拦截失效,修复要点如下:

1. 同时处理HTTP和HTTPS协议

原代码判断的是HTTPS开头的URL,但只注册了HTTP协议的处理器。新版Electron中protocol.handle需要分别为http和https注册处理器,否则HTTPS请求不会被拦截。

2. 转发请求时保留完整响应信息

原代码仅返回拼接的Buffer,新版需要传递原始响应的状态码、响应头等信息,否则页面可能无法正常渲染。

3. 完善错误处理逻辑

给net.request添加错误监听,避免请求失败时出现未处理的Promise拒绝。

修复后的完整代码

const { protocol, net } = require('electron');
const fs = require('fs').promises;
const { readFileSync } = require('fs');

function SetupIntercept() {
    // 同时注册HTTP和HTTPS协议处理器
    ['http', 'https'].forEach(scheme => {
        protocol.handle(scheme, async (req) => {
            // 替换为你需要拦截的目标URL
            const targetUrl = 'https://www.google.com/recaptcha/api2/demo';
            if (req.url === targetUrl) {
                try {
                    const html = await fs.readFile(`${__dirname}/captcha.html`, 'utf8');
                    return new Response(html, {
                        headers: { 'Content-Type': 'text/html' }
                    });
                } catch (err) {
                    console.error('读取captcha.html失败:', err);
                    return new Response('加载页面失败', {
                        status: 500,
                        headers: { 'Content-Type': 'text/plain' }
                    });
                }
            } else {
                return new Promise((resolve, reject) => {
                    const request = net.request(req);
                    
                    // 监听请求错误
                    request.on('error', (error) => {
                        console.error('请求出错:', error);
                        reject(new Response('请求失败', {
                            status: 500,
                            headers: { 'Content-Type': 'text/plain' }
                        }));
                    });

                    request.on('response', (res) => {
                        const chunks = [];
                        res.on('data', (chunk) => chunks.push(chunk));
                        res.on('end', () => {
                            const data = Buffer.concat(chunks);
                            // 构建Response,保留原始状态码和响应头
                            const response = new Response(data, {
                                status: res.statusCode,
                                headers: res.headers
                            });
                            resolve(response);
                        });
                        res.on('error', (error) => {
                            console.error('响应出错:', error);
                            reject(new Response('加载页面失败', {
                                status: 500,
                                headers: { 'Content-Type': 'text/plain' }
                            }));
                        });
                    });

                    if (req.uploadData) {
                        req.uploadData.forEach((part) => {
                            if (part.bytes) {
                                request.write(part.bytes);
                            } else if (part.file) {
                                request.write(readFileSync(part.file));
                            }
                        });
                    }

                    request.end();
                });
            }
        });
    });
}

额外注意事项

  • 必须在app.whenReady()之后调用SetupIntercept(),Electron的协议API需要在应用就绪后才能使用。
  • 如果目标URL存在重定向或带查询参数,需要调整req.url的匹配逻辑(比如忽略查询参数、统一路径大小写)。
  • 新版Electron推荐使用Response对象返回拦截结果,比直接返回普通对象更规范,也更兼容浏览器端的处理逻辑。

内容的提问来源于stack exchange,提问作者JediSZN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 23:45:15