chrome插件添加ajax拦截功能

2020-05-28  本文已影响0人  halapro_liu

前言

通过chrome插件的注入js脚本的功能,重写XMLHttpRequest方法,从而实现拦截ajax功能。

实现方式

首先通过content_script注入脚本inject/main.js

// 注入main.js到页面
var file = chrome.extension.getURL('inject/main.js')
var s = document.createElement('script')
s.type = 'text/javascript'
s.src = file
document.documentElement.appendChild(s)

// 传递参数到background页面
window.addEventListener('injectScript', (event) => {
  console.log(event.detail)
  chrome.runtime.sendMessage({
    type: 'demo',
    data: event.detail.data
  }, (response) => {
    console.log('demo response:', response)
  })
})

需要在manifest.json中添加配置,否则无法注入

{
  "web_accessible_resources": ["inject/main.js"]
}

核心代码:

let interceptor = {
  urls: [],
  originalXHR: window.XMLHttpRequest,
  myXHR: function () {
    let isScriptDispatched = false
    const modifyResponse = () => {
      if (!isScriptDispatched) {
        let matchUrls = interceptor.urls.filter(url => xhr.responseURL.indexOf(url) > -1)
        let match = matchUrls.length > 0
        if (match) {
          let data;
          if (!xhr.responseType || xhr.responseType === "text") {
              data = xhr.responseText;
          } else if (xhr.responseType === "document") {
              data = xhr.responseXML;
          } else {
              data = xhr.response;
          }
          this.responseText = this.response = data
          let detail = { url: xhr.responseURL, data }
          window.dispatchEvent(new CustomEvent("injectScript", { detail }));
          isScriptDispatched = true
        }
      }
    }
    const xhr = new interceptor.originalXHR
    for (let attr in xhr) {
      if (attr === 'onreadystatechange') {
        xhr.onreadystatechange = (...args) => {
          if (this.readyState === 4) {
            modifyResponse()
          }
          this.onreadystatechange && this.onreadystatechange.apply(this, args)
        }
        continue
      } else if (attr === 'onload') {
        xhr.onload = (...args) => {
          modifyResponse()
          this.onload && this.onload.apply(this, args)
        }
        continue
      }

      if (typeof xhr[attr] === 'function') {
        this[attr] = xhr[attr].bind(xhr);
      } else {
        // responseText和response不是writeable的,但拦截时需要修改它,所以修改就存储在this[`_${attr}`]上
        if (attr === 'responseText' || attr === 'response') {
          Object.defineProperty(this, attr, {
            get: () => this[`_${attr}`] == undefined ? xhr[attr] : this[`_${attr}`],
            set: (val) => this[`_${attr}`] = val,
            enumerable: true
          });
        } else {
          Object.defineProperty(this, attr, {
            get: () => xhr[attr],
            set: (val) => xhr[attr] = val,
            enumerable: true
          });
        }
      }
    }
  }
}


window.XMLHttpRequest = interceptor.myXHR
上一篇下一篇

猜你喜欢

热点阅读