赞
踩
关于chrome扩展拦截浏览器中请求数据,目前能找到的有三种方式实现,我都尝试过,下面是我个人的见解,欢迎指正。
方式一:通过chrome API提供的 webRequest的方法进行 拦截
优点:后台运行,用户无感知
缺点:官方出于安全考虑,无法获取到 请求的响应体内容
方式二:通过chrome扩展在content中 对页面注入js脚本 ,重写XMLHTTPRequest的方式进行监听
优点:能获取到请求的响应体,用户无感知
缺点:获取内容不全面,请求头 响应头 获取不全
因为大部分请求头都是在XHR处理完之后,由浏览器又新增一部分内容
方式三:开启浏览器调试模式
优点:能获取到全面的内容,包括请求头中的 session 信息
缺点:使用过程中 页面上方会有个 消息提示,,用户体验感不好调试的开启方式 是逐个标签页进行调试模式开启,需要对 tab 的新增进行监听
注:消息提示,可以在浏览器启动时,加上 '-silent-debugger-extension-api',来取消消息框
总结:为了获取到最全面的请求内容,且考虑用户体验 ,最后使用了第一种和第二种结合的方式
原理:content部分的原理是,通过注入inject.js重写 XmlHTTPRequest方法 ,在调用open方法的时候,监听 ‘load’事件获取响应后的 XHR对象,从对象里获取( 响应数据,请求数据),并发送给content,content在将消息发送给background处理;
chrome扩展中manifest.json的配置信息
注:1.必须用 content.js 获取document注入js的方式,content.js运行是不会影响到 页面中的方法。
2.run_at 需要在document_start 的时候进行注入并调用,这样当页面刷新时候发送的XHR请求也能拦截到,否则只能拦截到页面渲染之后 触发的请求内容
3.使用all_frames:true,这样即使页面中存在iframe也能进行注入,并拦截到请求内容
- "content_scripts":[
- {
- "matches":["<all_urls"],
- "js":["/content.js"],
- "run_at":"document_start",
- "all_frames":true
- }
- ],
-
- "web_accessible_resources":["/inject.js"],
content.js中的代码
注:1.需要使用document.creatElement的方式创建script,content注入的时机是 document_start,此时document找不到任何元素标签,网上 使用的 找到header的方式 无法使用,因为根本找不到;
- window.addEventListener("message",function(msg){
- console.log(msg);
- },false)
-
- // 注入方法
-
- let jsPath = '/inject.js'
- var temp = document.createElement('script')
- temp.setAttribute('type','text/javascript');
- temp.src = chrome.exetension.getURL(jspath);
- temp.onload = function(){
- this.parentNode.removeChild(this);
- }
- document.head.apppendChild(temp);
-
-
inject.js中的代码
注:inject.js 会在当前页面运行,影响到原有的代码逻辑,如果作为测试辅助工具,建议不要使用 下边三个变量名,改为比较复杂且不易重复的变量名,我在使用过程中发现 变量名 open会影响到 windows.open语法的使用,出现报错
- var XHR = XMLHttpRequest.prototype
- var open = XHR.open;
- var send = XHR.send;
-
-
-
- XHR.send = function(postData){
- this['hookQuery'] = postData
- return send.apply(this,arguments);
- }
-
- XHR.open = function(method,url){
- this._method = method;
- this._url = url;
-
- this.addEventListener("load",function(){
-
- window.postMessage({
- ...
- },"*")
- }
- return open.apply(this,arguments)
- }
原理:定义一个全局的map,background中通过webRequest提供的API进行 请求监听,获取到的数据存入map中,然后获取content中的消息之后 根据 tabId 请求方式 路径,去map中匹配,匹配成功之后,将两部分的数据进行组装发送到后台,特别需要注意的是:时机问题,content获取到数据前,此时background就已经获取到请求数据,不会出现匹配不到的问题。
background 监听content 消息
- chrome.runtime.onMessage.addListener(function(request,sender,sendResponse){
- sendResponse('received');
- '''
- 获取reqeust,sender中的数据内容,并进行匹配拼装,发送到后台
- '''
-
- })
background监听请求信息
- chrome.webRequest.onBeforeSendHeaders.addListener(details =>{
-
- '''
- 获取到请求数据之后,新增到map中
- '''
- },{urls:["<all_urls>"]},['requestHeaders'])
- chrome.webRequest.onCompleted.addListener(details =>{
-
- '''
- 获取到响应数据之后,查找请求信息组装到map中
- '''
- },{urls:["<all_urls>"]},['requestHeaders'])
注意事项:
background中的全局map 匹配成功之后要定时清理,监听到的请求内容进行筛选,是xmlHttpRequest类型的才能存入map,且map 需要定时清理,存的太多,不知道会不会影响 浏览器的性能
上述方案,亲测有效,并以投入生产运行,其中 inject的监听方式,content的注入时机采用过很多网上提供的方式,发现存在很多坑,上述代码是目前的最优解,如果有问题欢迎私信我,大家一起探讨。
来 看美女了。。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。