Tập lệnh nội dung là các tệp chạy trên ngữ cảnh của trang web. Bằng cách sử dụng Mô hình đối tượng tài liệu (DOM) tiêu chuẩn, các tiện ích này 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 các thay đổi đối với các trang web đó và chuyển thông tin đến tiện ích mẹ.
Tìm hiểu về 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 vào các API Chrome mà tiện ích mẹ của chúng sử dụng bằng cách trao đổi thông báo với tiện ích đó. Họ cũng có thể truy cập vào URL của tệp có tiện ích bằng
chrome.runtime.getURL()
rồi 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:
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 các thế giới riêng biệt
Tập lệnh nội dung hoạt động trong một thế giới riêng biệt, cho phép tập lệnh nội dung thực hiện các thay đổi đối với môi trường JavaScript mà không xung đột với trang hoặc các tập lệnh nội dung bổ sung.
Một 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.
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 do người khác tạo. Điều này cũng giúp tập lệnh nội dung có thể bật chức năng không được phép truy cập vào trang web.
Chèn tập lệnh
Bạn có thể chèn Tập lệnh nội dung theo phương thức lập trình hoặc theo cách khai báo.
Chèn theo phương thức lập trình
Sử dụng tính năng chèn theo lập trình cho các tập lệnh nội dung cần chạy vào những dịp cụ thể.
Để chèn tập lệnh nội dung có lập trình, hãy cấp quyền activeTab trong tệp kê khai. Thao tác 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 các thẻ cho phép tập lệnh nội dung chạy trên thẻ hiện đang hoạt động 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 có thể chèn toàn bộ tệp.
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 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 được đăng ký trong tệp kê khai trong trường "content_scripts"
.
Các tệp này 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 khớp.
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"css": ["myStyles.css"],
"js": ["contentScript.js"]
}
],
...
}
Tên | Loại | Mô tả |
---|---|---|
matches {: #matches } |
Bắt buộc. Chỉ định những trang sẽ được chèn tập lệnh nội dung này. Hãy xem phần Mẫu khớp để biết thêm thông tin chi tiết về cú pháp của các chuỗi này và phần Mẫu khớp và glob để biết thông tin về cách loại trừ URL. | |
css {: #css } |
Không bắt buộc. Danh sách các tệp CSS cần chèn vào các trang trùng khớp. Các phần tử này được chèn theo thứ tự xuất hiện trong mảng này, trước khi bất kỳ DOM nào được xây dựng hoặc hiển thị cho trang. | |
js {: #js } |
Không bắt buộc. Danh sách tệp JavaScript sẽ được đưa vào các trang phù hợp. Các biến 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. Tập lệnh có nên chèn vào một khung about:blank , nơi 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à khối hình cầu
Bạn có thể tuỳ chỉnh tính năng so khớp trang đã chỉ định bằng cách đưa các trường sau vào quá trình đăng ký tệp kê khai.
Tên | Loại | Mô tả |
---|---|---|
exclude_matches {: #exclude_matches } |
Không bắt buộc. Loại trừ các trang mà tập lệnh nội dung này sẽ được chèn vào. Hãy xem phần Mẫu khớp để biết thêm thông tin chi tiết về cú pháp của các chuỗi này. | |
include_globs {: #include_globs } |
Không bắt buộc. Được áp dụng sau matches để chỉ bao gồm những URL cũng khớp với glob này. Nhằm mô phỏng @include từ khoá Grease sao. |
|
exclude_globs {: #exclude_globs } |
Không bắt buộc. Được áp dụng sau ngày matches để loại trừ những URL khớp với khối cầu này. Dùng để mô phỏng từ khoá Greasemonkey @exclude . |
Tập lệnh nội dung sẽ được chèn vào một trang nếu URL của trang đó khớp với mẫu matches
bất kỳ và
include_globs
, miễn là URL không khớp với một mẫu exclude_matches
hoặc
Hoa văn exclude_globs
.
Vì thuộc tính matches
là bắt buộc, nên bạn chỉ có thể sử dụng exclude_matches
, include_globs
và exclude_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 nhưng không phải http://www.nytimes.com/ doanh nghiệp .
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"exclude_matches": ["*://*/*business*"],
"js": ["contentScript.js"]
}
],
...
}
Các thuộc tính glob tuân theo một cú pháp khác và linh hoạt hơn so với mẫu so khớp. Hình tròn có thể chấp nhận chuỗi là các URL có thể chứa "ký tự đại diện" dấu hoa thị và dấu chấm hỏi. Dấu hoa thị * khớp với chuỗi bất kỳ có độ dài bất kỳ, bao gồm cả chuỗi trống, trong khi dấu chấm hỏi ? khớp với một ký tự bất kỳ.
Ví dụ: biểu thức chính quy http:// ??? .example.com/foo/ * khớp với bất kỳ nội dung nào sau đây:
- http:// www .vidu.com/foo /bar
- http:// the .example.com/foo /
Tuy nhiên, mã này không phù hợp với những điều sau:
- http:// .example.com/foo/bar
- http:// example .com/foo/
- http://www.vidu.com/foo
Tiện ích này sẽ chèn tập lệnh nội dung vào http:/www.nytimes.com/ arts /index.html và http://www.nytimes.com/ jobs /index.html nhưng không chèn 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.com và http://.nytimes.com/ lịch sử nhưng không vào http:// Science .nytimes.com hoặc http://www.nytimes.com/ khoa học .
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"exclude_globs": ["*science*"],
"js": ["contentScript.js"]
}
],
...
}
Bạn có thể sử dụng một, tất cả hoặc một vài trong số đó để đạ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 đưa vào trang web sẽ do trường run_at
kiểm soát. Chiến lược phát hành đĩa đơn
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 | Mô tả |
---|---|---|
document_idle {: #document_idle } |
chuỗi | Ưu tiên. 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 giữa "document_end" và 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 và thời gian tải tài liệu, đồng thời được tối ưu hoá cho tốc độ tải trang.Các tập lệnh nội dung chạy tại "document_idle" không cần phải theo dõi sự kiện window.onload , mà chúng đả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 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 } |
chuỗi | Các tập lệnh được chèn sau mọi tệp từ css , nhưng trước khi tạo bất kỳ DOM nào khác hoặc chạy bất kỳ tập lệnh nào khác. |
document_end {: #document_end } |
chuỗi | Các 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 được tải. |
Chỉ định khung
Trường "all_frames"
cho phép tiện ích chỉ định liệu có phải tệp JavaScript và CSS hay không
được chèn vào tất cả các khung phù hợp với các yêu cầu URL được chỉ định hoặc chỉ vào khung trên cùng trong một
.
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"all_frames": true,
"js": ["contentScript.js"]
}
],
...
}
Tên | Loại | Mô tả |
---|---|---|
all_frames {: #all_frames } |
boolean | Không bắt buộc. Giá trị mặc định là false , nghĩa là chỉ khung hình trên cùng được so khớp.Nếu bạn chỉ định true , khung này sẽ được chèn vào mọi khung hình, ngay cả khi khung hình đó không phải là khung hình trên cùng trong thẻ. Mỗi khung được kiểm tra độc lập theo các yêu cầu về URL, khung sẽ không chèn vào các khung con nếu không đáp ứng các yêu cầu về URL. |
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 được tách biệt với nhau, nhưng các môi trường này có quyền truy cập chung 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 tiện ích thông qua tập lệnh nội dung, trang phải thực hiện việc này thông qua DOM dùng chung.
Bạn có thể thực hiện ví dụ này 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, đăng thông báo lên chính trang đó. Thông báo này được tập lệnh nội dung chặn và kiểm tra, sau đó được đăng lên quy trình mở rộng. Bằng cách này, trang này sẽ thiết lập một đường liên lạc đến quy trình mở rộng. Điều ngược lại có thể thực hiện thông qua có nghĩa tương tự.
Bảo mật
Mặc dù các thế giới tách biệt mang đến 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 lỗ hổng bảo mật 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 riêng biệt trên trang web, chẳng hạn như tạo một XMLHttpRequest, hãy cẩn thận lọc nội dung trên nhiều trang web tập lệnh trước khi chèn tập lệnh đó. Chỉ giao tiếp qua HTTPS để tránh các cuộc tấn công "xen giữa".
Nhớ lọc ra 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 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);