Tập lệnh nội dung

Tập lệnh nội dung là các tệp chạy trong ngữ cảnh của các trang web. Khi sử dụng Mô hình đối tượng tài liệu (DOM), trình duyệt có thể đọc thông tin chi tiết về các trang web mà trình duyệt truy cập, thực hiện thay đổi đối với các trang đó và chuyển thông tin tới tiện ích mẹ.

Tìm hiểu các chức năng của tập lệnh nội dung

Tập lệnh nội dung có thể truy cập các API Chrome mà tiện ích gốc sử dụng bằng cách trao đổi thông báo với tiện ích đó. Các URL này cũng có thể truy cập URL tệp của một tiện ích bằng chrome.runtime.getURL() và sử dụng kết quả giống như các URL khác.

// Code for displaying EXTENSION_DIR/images/myimage.png:
var imgURL = chrome.runtime.getURL("images/myimage.png");
document.getElementById("someImage").src = imgURL;

Ngoài ra, tập lệnh nội dung có thể truy cập trực tiếp vào các API Chrome sau đây:

Tập lệnh nội dung không thể truy cập trực tiếp vào các API khác.

Làm việc trong thế giới tách biệt

Tập lệnh nội dung nằm trong một thế giới riêng biệt, cho phép một tập lệnh nội dung thay đổi môi trường JavaScript mà không xung đột với trang hoặc tập lệnh nội dung bổ sung.

Tiện ích có thể chạy trong trang web có mã tương tự như ví dụ bên dưới.

<html>
  <button id="mybutton">click me</button>
  <script>
    var greeting = "hello, ";
    var button = document.getElementById("mybutton");
    button.person_name = "Bob";
    button.addEventListener("click", function() {
      alert(greeting + button.person_name + ".");
    }, false);
  </script>
</html>

Tiện ích đó có thể chèn tập lệnh nội dung sau.

var greeting = "hola, ";
var button = document.getElementById("mybutton");
button.person_name = "Roberto";
button.addEventListener("click", function() {
  alert(greeting + button.person_name + ".");
}, false);

Cả hai cảnh báo sẽ xuất hiện nếu bạn nhấn nút này.

Các thế giới tách biệt không cho phép tập lệnh nội dung, tiện ích và trang web truy cập vào bất kỳ biến hoặc hàm nào do người khác tạo. Ngoài ra, tập lệnh nội dung cũng có thể bật chức năng mà trang web không thể truy cập được.

Chèn tập lệnh

Tập lệnh nội dung có thể được chèn theo phương thức lập trình hoặc khai báo.

Chèn theo phương thức lập trình

Sử dụng tính năng chèn có lập trình cho tập lệnh nội dung cần chạy vào những dịp cụ thể.

Để chèn một tập lệnh nội dung có lập trình, hãy cung cấp quyền activeTab trong tệp kê khai. Điều này cấp quyền truy cập an toàn vào máy chủ lưu trữ của trang web đang hoạt động và quyền truy cập tạm thời vào thẻ, cho phép tập lệnh nội dung chạy trên thẻ đang hoạt động hiện tại mà không cần chỉ định quyền trên nhiều nguồn gốc.

{
  "name": "My extension",
  ...
  "permissions": [
    "activeTab"
  ],
  ...
}

Tập lệnh nội dung có thể được chèn dưới dạng mã.

chrome.runtime.onMessage.addListener(
  function(message, callback) {
    if (message == "changeColor"){
      chrome.tabs.executeScript({
        code: 'document.body.style.backgroundColor="orange"'
      });
    }
  });

Hoặc bạn có thể chèn toàn bộ tệp vào.

chrome.runtime.onMessage.addListener(
  function(message, callback) {
    if (message == "runContentScript"){
      chrome.tabs.executeScript({
        file: 'contentScript.js'
      });
    }
  });

Chèn theo cách khai báo

Sử dụng tính năng chèn nội dung khai báo cho các tập lệnh nội dung sẽ tự động chạy trên các trang được chỉ định.

Các tập lệnh được chèn theo cách khai báo sẽ được đăng ký trong tệp kê khai thuộc trường "content_scripts". Chúng có thể bao gồm tệp JavaScript, tệp CSS hoặc cả hai. Tất cả tập lệnh nội dung tự động chạy phải chỉ định mẫu so khớp.

{
 "name": "My extension",
 ...
 "content_scripts": [
   {
     "matches": ["http://*.nytimes.com/*"],
     "css": ["myStyles.css"],
     "js": ["contentScript.js"]
   }
 ],
 ...
}
Tên Loại Nội dung mô tả
matches {: #match } mảng chuỗi Bắt buộc. Chỉ định những trang mà tập lệnh nội dung này sẽ được đưa vào. Hãy xem phần Mẫu so khớp để biết thêm thông tin chi tiết về cú pháp của các chuỗi này cũng như Mẫu và cụm từ so khớp để biết thông tin về cách loại trừ URL.
css {: #css } mảng chuỗi Không bắt buộc. Danh sách các tệp CSS được đưa vào các trang phù hợp. Các lệnh này được đưa vào theo thứ tự xuất hiện trong mảng này, trước khi bất kỳ DOM nào được tạo hoặc hiển thị cho trang.
js {: #js } mảng chuỗi Không bắt buộc. Danh sách tệp JavaScript được đưa vào các trang phù hợp. Các đối số này được chèn theo thứ tự xuất hiện trong mảng này.
match_about_blank {: #match_about_blank } boolean Không bắt buộc. Liệu tập lệnh có nên chèn vào khung about:blank, trong đó khung mẹ hoặc khung mở khớp với một trong các mẫu được khai báo trong matches hay không. Giá trị mặc định là false.

Loại trừ kết quả trùng khớp và toàn cầu

Bạn có thể tuỳ chỉnh hoạt động so khớp trang đã chỉ định bằng cách đưa các trường sau vào phần đăng ký tệp kê khai.

Tên Loại Nội dung mô tả
exclude_matches {: #Exclude_match } mảng chuỗi Không bắt buộc. Không bao gồm những trang mà tập lệnh nội dung này sẽ được chèn vào. Xem Mẫu so khớp để biết thêm chi tiết về cú pháp của các chuỗi này.
include_globs {: #include_globs } mảng chuỗi Không bắt buộc. Được áp dụng sau matches để chỉ bao gồm các URL cũng khớp với toàn bộ tập hợp này. Nhằm mục đích mô phỏng từ khoá Gr trazok @include.
exclude_globs {: #Exclude_globs } mảng chuỗi Không bắt buộc. Được áp dụng sau matches để loại trừ các URL khớp với tập hợp nhỏ này. Nhằm mục đích mô phỏng @exclude từ khoá Mỡ mỡ.

Tập lệnh nội dung sẽ được chèn vào trang nếu URL của trang đó khớp với mẫu matches bất kỳ và mẫu include_globs bất kỳ, miễn là URL đó cũng không khớp với mẫu exclude_matches hoặc exclude_globs.

Vì bắt buộc phải có thuộc tính matches, nên bạn chỉ có thể dùng exclude_matches, include_globsexclude_globs để giới hạn những trang sẽ bị ảnh hưởng.

Tiện ích sau sẽ chèn tập lệnh nội dung vào http://www.nytimes.com/ health chứ không chèn tập lệnh vào http://www.nytimes.com/ business .

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "exclude_matches": ["*://*/*business*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

Thuộc tính glob tuân theo cú pháp khác, linh hoạt hơn so với mẫu so khớp. Chuỗi hình cầu được chấp nhận là các URL có thể chứa dấu hoa thị "ký tự đại diện" và dấu chấm hỏi. Dấu hoa thị * khớp với mọi chuỗi có độ dài bất kỳ, kể cả chuỗi trống, trong khi dấu chấm hỏi ? khớp với bất kỳ ký tự đơn nào.

Ví dụ: glob http:// ? .example.com/foo/ * khớp với bất kỳ kết quả nào sau đây:

  • http:// www .example.com/foo /bar
  • http:// .example.com/foo /

Tuy nhiên, thẻ này không khớp với những yêu cầu sau:

  • http:// .example.com/foo/bar của tôi
  • http:// example .com/foo/
  • http://www.example.com/foo

Tiện ích này sẽ chèn tập lệnh nội dung vào http:/www.nytimes.com/ artists /index.htmlhttp://www.nytimes.com/ job /index.html nhưng không chèn tập lệnh nội dung vào http://www.nytimes.com/ Sports/index.html.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "include_globs": ["*nytimes.com/???s/*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

Tiện ích này sẽ chèn tập lệnh nội dung vào http:// history .nytimes.comhttp://.nytimes.com/ history chứ không chèn nội dung vào http:// science .nytimes.com hay http://www.nytimes.com/ science .

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "exclude_globs": ["*science*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

Bạn có thể đưa một, tất cả hoặc một số phần tử trong số đó vào để đạt được phạm vi chính xác.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "exclude_matches": ["*://*/*business*"],
      "include_globs": ["*nytimes.com/???s/*"],
      "exclude_globs": ["*science*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

Thời gian chạy

Khi các tệp JavaScript được chèn vào trang web, trường run_at sẽ kiểm soát. Trường mặc định và được ưu tiên là "document_idle", nhưng cũng có thể được chỉ định là "document_start" hoặc "document_end" nếu cần.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "run_at": "document_idle",
      "js": ["contentScript.js"]
    }
  ],
  ...
}
Tên Loại Nội dung mô tả
document_idle {: #document_idle } string Ưu tiên. Hãy sử dụng "document_idle" bất cứ khi nào có thể.

Trình duyệt chọn thời điểm để chèn tập lệnh trong khoảng từ "document_end" đến ngay sau khi sự kiện windowonload kích hoạt. Thời điểm chèn chính xác phụ thuộc vào độ phức tạp của tài liệu và thời gian tải, đồng thời được tối ưu hoá cho tốc độ tải trang.

Tập lệnh nội dung chạy ở "document_idle" không cần theo dõi sự kiện window.onload, chúng được đảm bảo sẽ chạy sau khi DOM hoàn tất. Nếu một tập lệnh chắc chắn cần chạy sau window.onload, thì tiện ích này có thể kiểm tra xem onload đã kích hoạt hay chưa bằng cách sử dụng thuộc tính document.readyState.
document_start {: #document_start } string Các tập lệnh được chèn sau bất kỳ tệp nào từ css, nhưng trước khi bất kỳ DOM nào khác được tạo hoặc bất kỳ tập lệnh nào khác được chạy.
document_end {: #document_end } string Tập lệnh được chèn ngay sau khi DOM hoàn tất, nhưng trước khi các nguồn phụ như hình ảnh và khung tải xong.

Chỉ định khung

Trường "all_frames" cho phép tiện ích chỉ định xem có nên chèn tệp JavaScript và CSS vào tất cả các khung phù hợp với các yêu cầu về URL đã chỉ định hay chỉ vào khung trên cùng trong một thẻ.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "all_frames": true,
      "js": ["contentScript.js"]
    }
  ],
  ...
}
Tên Loại Nội dung mô tả
all_frames {: #all_frames } boolean Không bắt buộc. Giá trị mặc định là false, nghĩa là chỉ có khung trên cùng được khớp.

Nếu được chỉ định true, thì đối tượng này sẽ được chèn vào tất cả khung hình, ngay cả khi khung đó không phải là khung trên cùng trong thẻ. Mỗi khung sẽ được kiểm tra độc lập về các yêu cầu về URL và sẽ không được đưa vào khung con nếu các yêu cầu về URL không được đáp ứng.

Giao tiếp với trang nhúng

Mặc dù môi trường thực thi của tập lệnh nội dung và các trang lưu trữ tập lệnh nội dung bị tách biệt với nhau, nhưng các môi trường này chia sẻ quyền truy cập vào DOM của trang. Nếu muốn giao tiếp với tập lệnh nội dung hoặc với phần mở rộng thông qua tập lệnh nội dung, thì trang phải thực hiện điều đó thông qua DOM dùng chung.

Bạn có thể thực hiện một ví dụ bằng cách sử dụng window.postMessage:

var port = chrome.runtime.connect();

window.addEventListener("message", function(event) {
  // We only accept messages from ourselves
  if (event.source != window)
    return;

  if (event.data.type && (event.data.type == "FROM_PAGE")) {
    console.log("Content script received: " + event.data.text);
    port.postMessage(event.data.text);
  }
}, false);
document.getElementById("theButton").addEventListener("click",
    function() {
  window.postMessage({ type: "FROM_PAGE", text: "Hello from the webpage!" }, "*");
}, false);

Trang không có tiện ích, example.html, sẽ đăng thông báo lên chính trang đó. Tập lệnh nội dung sẽ chặn và kiểm tra thông báo này, sau đó được đăng lên quy trình tiện ích. Theo cách này, trang thiết lập một kênh giao tiếp với quy trình tiện ích. Điều ngược lại cũng có thể xảy ra thông qua các cách tương tự.

Giữ an toàn

Mặc dù những thế giới tách biệt cung cấp một lớp bảo vệ, nhưng việc sử dụng tập lệnh nội dung có thể tạo ra các lỗ hổng trong tiện ích và trang web. Nếu tập lệnh nội dung nhận được nội dung từ một trang web riêng biệt, chẳng hạn như tạo XMLHttpRequest, hãy cẩn thận lọc bỏ các cuộc tấn công tập lệnh trên nhiều trang web trước khi chèn nội dung đó. Chỉ giao tiếp qua HTTPS để tránh bị tấn công "man-in-the-middle".

Hãy nhớ lọc các trang web độc hại. Ví dụ: các mẫu sau đây là nguy hiểm:

var data = document.getElementById("json-data")
// WARNING! Might be evaluating an evil script!
var parsed = eval("(" + data + ")")
var elmt_id = ...
// WARNING! elmt_id might be "); ... evil script ... //"!
window.setTimeout("animate(" + elmt_id + ")", 200);

Thay vào đó, hãy ưu tiên các API an toàn hơn mà không chạy tập lệnh:

var data = document.getElementById("json-data")
// JSON.parse does not evaluate the attacker's scripts.
var parsed = JSON.parse(data);
var elmt_id = ...
// The closure form of setTimeout does not evaluate scripts.
window.setTimeout(function() {
  animate(elmt_id);
}, 200);