Electron获取webview中ajax请求内容的方法

Electron中,可以通过WebRequest监听webview中请求的各个阶段,并且获取或修改请求头和响应头。

但却没有提供获取请求内容的方法。那么如何获取请求内容呢?

首先,我们可以通过比较暴力的方法,就是在webRequest.onCompleted时,重新利用如http模块,对url再发送一次请求,从而获取请求内容。

但这个方法也有弊端,那就是,某些ajax请求,是不能重复的,尤其是POST请求。

比如一个点赞功能,第一次请求服务端会返回成功。第二次再请求,服务端就会报错了。

那么如何做才能直接获取到ajax请求的内容呢?

接下来,我教大家一种方法,就是

利用webview的preload功能,劫持原生XHRHttpRequest类,来实现在Electron中获取ajax请求内容

原理是,Electron的webview标签,有个preload属性,可以在页面加载之前,注入指定的js脚本,并且这个js脚本是一定集成了node环境的。

那么我们就可以在这个脚本中,将原生的XHRHttpRequest类替换掉。每当页面中通过XHRHttpRequest发送ajax请求是,我们就可以先拿到内容,再返回给页面了。废话不多说,直接上代码

代码基于ES6 

const READY_STATE_CHANGE = 'readystatechange';

let gHandlerList = [],//截获请求的处理函数列表

    gIsInited = false;//是否已经初始化

let T_RSC_HANDLERS = Symbol('readyStateChangeHandler');

let initProxy = function(){

    if(gIsInited)return;

    gIsInited = true;

    //这里先缓存一份原生的XMLHttpRequest类

    let winXMLHttpRequest = window.XMLHttpRequest;

    //用于替换原生XMLHttpRequest的类,继承自XMLHttpRequest

    let ProxyXHR = class extends winXMLHttpRequest{

        constructor(){

            super(...arguments);

            //readystatechange

            //数组中第0个为页面中调用xhr.onreadystatechange的回调函数

            //其他的为页面中调用addEventListener('readystatechange')时的回调函数

            this[T_RSC_HANDLERS] = [null];

            //调用原生XMLHttpRequest的addEventListener,添加对readystatechange事件的监听

            super.addEventListener(READY_STATE_CHANGE,async ()=>{

                if(this.readyState == 4 && gHandlerList.length){//只有4的时候会回调proxyHandler

                    try{

                        //调用注册的handler

                        await gHandlerList.map(proxyHandler => proxyHandler.call(this,this));

                    }

                    catch(e){

                        //TODO 这里可以替换为其他的错误处理逻辑

                        console.error(e);

                    }

                }

                //调用页面中注册的回调函数,保证页面中逻辑正常

                this[T_RSC_HANDLERS].forEach(handler => handler && handler.apply(this,arguments));

            });

        }

        /**

        * 重写addEventListener函数,对readystatechange事件做特殊处理

        */

        addEventListener(type,handler){

            if(type == READY_STATE_CHANGE){

                this[T_RSC_HANDLERS].push(handler);

            }

            else{

                return super.addEventListener(...arguments);

            }

        }

        /**

        * 重写removeEventListener函数,对readystatechange事件做特殊处理

        */

        removeEventListener(type,handler){

            if(type == READY_STATE_CHANGE){

                this[T_RSC_HANDLERS] = this[T_RSC_HANDLERS].filter(i => i!== handler);

            }

            else{

                return super.removeEventListener(...arguments);

            }

        }

        /**

        * 重写onreadystatechange属性的setter

        */

        set onreadystatechange(val){

            this[T_RSC_HANDLERS][0] = val;

        }

        /**

        * 重写onreadystatechange属性的getter

        */

        get onreadystatechange(){

            return this[T_RSC_HANDLERS][0] || null;

        }

    }

    //覆盖原生的XMLHttpRequest

    window.XMLHttpRequest = ProxyXHR;

}

/**

* 增加一个handler

* 当xhr.readyState == 4时,回调handler,handler中,可以通过xhr.responseText获取请求返回内容

* @param {function} handler function(xhr){}

*/

let addHandler = function(handler){

    initProxy();

    gHandlerList.push(handler);

}

/**

* 移除指定的handler

* @param {function} handler 调用addHandler时添加的handler

*/

let removeHandler = function(handler){

    gHandlerList = gHandlerList.filter(h => h!== handler);

}

module.exports.addHandler = addHandler;

module.exports.removeHandler = removeHandler;

剩下的业务代码就简单了,获取到xhr后,简单处理,通过ipcRenderer.sendToHost即可将xhr内容发送到BrowserWindow中

/**

* preload.js

*/

const xhrProxy = require('./xhr_proxy.js');

const {ipcRenderer} = require('electron');

xhrProxy.addHandler(function(xhr){

    let data = {};

    //TODO 具体业务代码

    //通过ipcRenderer.sendToHost即可将xhr内容发送到BrowserWindow中

    ipcRenderer.sendToHost('channel',data);

});

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些阅读 2,028评论 0 2
  • Ajax和XMLHttpRequest 我们通常将Ajax等同于XMLHttpRequest,但细究起来它们两个是...
    changxiaonan阅读 2,227评论 0 2
  •   2005 年,Jesse James Garrett 发表了一篇在线文章,题为“Ajax: A new App...
    霜天晓阅读 883评论 0 1
  • JSON APIS and AJAX Description:*Introduction to the JSON ...
    王策北阅读 570评论 0 1
  • 不记得上次牙疼是什么时候!这两天又来一次洗礼,让我痛彻心扉地领悟到健康有多好!辗转反侧,夜不能寐的痛苦太让人难过了...
    自由飞翔的我阅读 265评论 0 0