เหตุใดรหัสนี้จึงใช้งานไม่ได้ ฉันกำลังสร้างส่วนขยาย Firefox แต่โค้ดไม่ทำงาน แต่ถ้าฉันวางโค้ดลงในคอนโซลมันก็ใช้งานได้

ฉันสร้างส่วนขยาย Firefox ที่ได้รับ URL คำขอทั้งหมดและแสดงไว้ แต่โค้ดจะใช้ได้เฉพาะเมื่อฉันวางลงในคอนโซลเท่านั้น

เมื่อโหลดส่วนขยายแล้ว มันไม่แสดงข้อผิดพลาดใด ๆ ดูเหมือนว่ามันจะไม่ทำงาน

นี่คือรหัสเต็ม

xhrScript.js

(function(){

    const proxiedOpen = XMLHttpRequest.prototype.open;
    window.XMLHttpRequest.prototype.open = function ( _, url) {
        this.__URL = url;
        return proxiedOpen.apply(this, arguments);
    };

    const proxiedSend = window.XMLHttpRequest.prototype.send;
    window.XMLHttpRequest.prototype.send = function () {
        const { protocol, host } = window.location;
        // showing only when it paste in console
        console.log("full request url ", `${protocol}//${host}${this.__URL}`);
        return proxiedSend.apply(this, [].slice.call(arguments));
    };

})();

// this works all times
document.body.style.border = "7px solid blue";

manifest.json

{
    "manifest_version": 2,
    "name": "XHR request urls",
    "version": "1.0",
    "description": "get all the request url's",

    "content_scripts": [
      {
        "matches": ["*://*/*"],
        "js": ["xhrScript.js"]
      }
    ]  
}

อย่างที่คุณเห็นในบรรทัดสุดท้ายคือ document.body.style.border = "7px solid blue"; ซึ่งใช้ได้ดีทุกครั้ง แต่วิธี XMLHttpRequest open และ send ใช้งานไม่ได้ ใช้งานได้เฉพาะเมื่อฉันวางโค้ดลงในคอนโซล

หากคุณต้องการดูตัวอย่าง คุณสามารถลองคัดลอกและวางโค้ด xhrScript.js ใน https://reactjs.org (เป็น SPA ดังนั้นจึงเป็นเรื่องง่ายที่จะตรวจสอบสิ่งที่ฉันต้องการ) ในคอนโซล devTools และดูคำขอทั้งหมด

ฉันไม่รู้ว่าทำไมรหัสนี้จึงทำงานเฉพาะเมื่อวางในคอนโซลเท่านั้น


person Carlos Martínez    schedule 13.11.2020    source แหล่งที่มา


คำตอบ (1)


สคริปต์เนื้อหาทำงานในสภาพแวดล้อม JavaScript แบบแยก ซึ่งหมายความว่า window และเนื้อหาจะถูกแยกออกจากเพจ ดังนั้นเมื่อคุณแก้ไขสคริปต์ คุณจะแก้ไขเฉพาะเวอร์ชันของสคริปต์เนื้อหาเท่านั้น

มีสองวิธีแก้ไข:

  1. เฉพาะ Firefox

    ใช้ wrappedJSObject และ exportFunction เพื่อเข้าถึงบริบทของหน้า (ข้อมูลเพิ่มเติม):

    const urls = new WeakMap();
    const origXhr = hookPagePrototype('XMLHttpRequest', {
      open(method, url) {
        urls.set(this, url);
        return origXhr.open.apply(this, arguments);
      },
      send() {
        console.log('Sending', new URL(urls.get(this), location).href);
        return origXhr.send.apply(this, arguments);
      },
    });
    
    function hookPagePrototype(protoName, funcs) {
      const proto = wrappedJSObject[protoName].prototype;
      const oldFuncs = {};
      for (const [name, fn] of Object.entries(funcs)) {
        oldFuncs[name] = exportFunction(proto[name], wrappedJSObject);
        proto[name] = exportFunction(fn, wrappedJSObject);
      }
      return oldFuncs;
    }
    
  2. รองรับ Chrome

    ใช้สคริปต์ DOM เพื่อเรียกใช้โค้ดในบริบทของหน้า: คำแนะนำ

    มันจะไม่ทำงานบนหน้าที่ป้องกันโดยนโยบายความปลอดภัยเนื้อหา (CSP) ที่เข้มงวดซึ่งป้องกันการเรียกใช้สคริปต์ ดังนั้นเมื่อเขียนส่วนขยายสำหรับ Firefox เราควรใช้วิธี wrappedJSObject แทน

person wOxxOm    schedule 13.11.2020
comment
ว้าว มันได้ผล ฉันยังใหม่กับการสร้างส่วนขยายเบราว์เซอร์มาก สิ่งนี้ช่วยฉันได้มาก ขอบคุณสำหรับการแบ่งปันเอกสาร - person Carlos Martínez; 13.11.2020