สคริปต์เนื้อหาคือไฟล์ที่ทำงานในบริบทของหน้าเว็บ โดยใช้ Document Object Model (DOM) มาตรฐาน ชิ้นงานเหล่านี้จะอ่านรายละเอียดของหน้าเว็บที่เบราว์เซอร์เข้าชม ทำการเปลี่ยนแปลง และส่งข้อมูลไปยังส่วนขยายหลักได้
ทําความเข้าใจความสามารถของสคริปต์เนื้อหา
สคริปต์เนื้อหาเข้าถึง API ต่อไปนี้ของส่วนขยายได้โดยตรง
dom
i18n
storage
runtime.connect()
runtime.getManifest()
runtime.getURL()
runtime.id
runtime.onConnect
runtime.onMessage
runtime.sendMessage()
สคริปต์เนื้อหาจะเข้าถึง API อื่นๆ โดยตรงไม่ได้ แต่สามารถเข้าถึงข้อมูลดังกล่าวได้แบบอ้อมโดยแลกเปลี่ยนข้อความกับส่วนอื่นๆ ของส่วนขยาย
นอกจากนี้ คุณยังเข้าถึงไฟล์อื่นๆ ในส่วนขยายจากสคริปต์เนื้อหาได้โดยใช้ API เช่น fetch()
โดยคุณต้องประกาศทรัพยากรดังกล่าวเป็นทรัพยากรที่เข้าถึงได้ทางเว็บ โปรดทราบว่าการดำเนินการนี้จะแสดงทรัพยากรแก่สคริปต์ของบุคคลที่หนึ่งหรือบุคคลที่สามที่ทำงานในเว็บไซต์เดียวกันด้วย
ทำงานในโลกที่แยกต่างหาก
สคริปต์เนื้อหาจะทำงานแยกต่างหาก ซึ่งช่วยให้สคริปต์เนื้อหาทำการเปลี่ยนแปลงสภาพแวดล้อม JavaScript ของตนได้โดยไม่ขัดแย้งกับหน้าเว็บหรือสคริปต์เนื้อหาของส่วนขยายอื่นๆ
ส่วนขยายอาจทํางานในหน้าเว็บที่มีโค้ดคล้ายกับตัวอย่างต่อไปนี้
webPage.html
<html>
<button id="mybutton">click me</button>
<script>
var greeting = "hello, ";
var button = document.getElementById("mybutton");
button.person_name = "Bob";
button.addEventListener(
"click", () => alert(greeting + button.person_name + "."), false);
</script>
</html>
ส่วนขยายดังกล่าวอาจแทรกสคริปต์เนื้อหาต่อไปนี้โดยใช้เทคนิคใดเทคนิคหนึ่งตามที่ระบุไว้ในส่วนแทรกสคริปต์
content-script.js
var greeting = "hola, ";
var button = document.getElementById("mybutton");
button.person_name = "Roberto";
button.addEventListener(
"click", () => alert(greeting + button.person_name + "."), false);
การเปลี่ยนแปลงนี้จะทำให้การแจ้งเตือนทั้ง 2 รายการปรากฏตามลำดับเมื่อมีการคลิกปุ่ม
แทรกสคริปต์
สคริปต์เนื้อหาสามารถประกาศแบบคงที่ ประกาศแบบไดนามิก หรือแทรกแบบเป็นโปรแกรม
แทรกด้วยประกาศแบบคงที่
ใช้การประกาศสคริปต์เนื้อหาแบบคงที่ในไฟล์ manifest.json สำหรับสคริปต์ที่ควรทำงานโดยอัตโนมัติในชุดหน้าเว็บที่รู้จักกันดี
สคริปต์ที่ประกาศแบบคงที่จะลงทะเบียนในไฟล์ Manifest ภายใต้คีย์ "content_scripts"
โดยอาจประกอบด้วยไฟล์ JavaScript, ไฟล์ CSS หรือทั้ง 2 ประเภท สคริปต์เนื้อหาที่ทำงานอัตโนมัติทั้งหมดต้องระบุรูปแบบการจับคู่
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.nytimes.com/*"],
"css": ["my-styles.css"],
"js": ["content-script.js"]
}
],
...
}
ชื่อ | ประเภท | คำอธิบาย |
---|---|---|
matches |
อาร์เรย์สตริง | ต้องระบุ ระบุหน้าที่ระบบจะแทรกสคริปต์เนื้อหานี้ ดูรายละเอียดเกี่ยวกับไวยากรณ์ของสตริงเหล่านี้ได้ที่รูปแบบการจับคู่ และดูข้อมูลเกี่ยวกับวิธียกเว้น URL ได้ที่รูปแบบการจับคู่และนิพจน์ทั่วไป |
css |
อาร์เรย์สตริง | ไม่บังคับ รายการไฟล์ CSS ที่จะแทรกลงในหน้าที่ตรงกัน รายการเหล่านี้จะแทรกตามลำดับที่ปรากฏในอาร์เรย์นี้ ก่อนที่ DOM จะสร้างขึ้นหรือแสดงสำหรับหน้าเว็บ |
js |
|
ไม่บังคับ รายการไฟล์ JavaScript ที่จะแทรกลงในหน้าเว็บที่ตรงกัน ระบบจะแทรกไฟล์ตามลำดับที่ปรากฏในอาร์เรย์นี้ สตริงแต่ละรายการในรายการนี้ต้องมี เส้นทางแบบสัมพัทธ์ไปยังแหล่งข้อมูลในไดเรกทอรีรูทของส่วนขยาย ระบบจะตัดเครื่องหมายทับ (`/`) ที่อยู่ด้านหน้าออกโดยอัตโนมัติ |
run_at |
RunAt | ไม่บังคับ ระบุเวลาที่ควรแทรกสคริปต์ลงในหน้าเว็บ ค่าเริ่มต้นคือ
document_idle |
match_about_blank |
บูลีน | ไม่บังคับ กำหนดว่าสคริปต์ควรแทรกลงในเฟรม about:blank หรือไม่ โดยที่เฟรมหลักหรือเฟรมเปิดตรงกับรูปแบบใดรูปแบบหนึ่งที่ประกาศไว้ใน matches ค่าเริ่มต้นคือ False |
match_origin_as_fallback |
บูลีน |
ไม่บังคับ กำหนดว่าสคริปต์ควรแทรกในเฟรมที่สร้างโดยต้นทางที่ตรงกัน แต่ URL หรือต้นทางอาจไม่ตรงกับรูปแบบโดยตรง ซึ่งรวมถึงเฟรมที่มีรูปแบบต่างกัน เช่น about: , data: , blob: และ filesystem: ดูการแทรกในเฟรมที่เกี่ยวข้องเพิ่มเติม
|
world |
ExecutionWorld |
ไม่บังคับ โลกของ JavaScript สําหรับให้สคริปต์ทํางาน ค่าเริ่มต้นคือ ISOLATED ดูข้อมูลเพิ่มเติมได้ที่ทํางานในสภาพแวดล้อมแบบแยกส่วน
|
แทรกด้วยประกาศแบบไดนามิก
สคริปต์เนื้อหาแบบไดนามิกมีประโยชน์เมื่อรูปแบบการจับคู่สําหรับสคริปต์เนื้อหานั้นไม่เป็นที่รู้จักมากนัก หรือเมื่อไม่ควรแทรกสคริปต์เนื้อหาในโฮสต์ที่รู้จักเสมอไป
การประกาศแบบไดนามิกซึ่งเปิดตัวใน Chrome 96 นั้นคล้ายกับการประกาศแบบคงที่ แต่ออบเจ็กต์สคริปต์เนื้อหาจะลงทะเบียนกับ Chrome โดยใช้เมธอดในเนมสเปซ chrome.scripting
แทนที่จะอยู่ใน manifest.json นอกจากนี้ Scripting API ยังช่วยให้นักพัฒนาส่วนขยายทำสิ่งต่อไปนี้ได้
- ลงทะเบียนสคริปต์เนื้อหา
- ดูรายการสคริปต์เนื้อหาที่ลงทะเบียน
- อัปเดตรายการสคริปต์เนื้อหาที่ลงทะเบียน
- นำสคริปต์เนื้อหาที่ลงทะเบียนออก
เช่นเดียวกับการประกาศแบบคงที่ การประกาศแบบไดนามิกอาจมีไฟล์ JavaScript, ไฟล์ CSS หรือทั้ง 2 ไฟล์
service-worker.js
chrome.scripting
.registerContentScripts([{
id: "session-script",
js: ["content.js"],
persistAcrossSessions: false,
matches: ["*://example.com/*"],
runAt: "document_start",
}])
.then(() => console.log("registration complete"))
.catch((err) => console.warn("unexpected error", err))
service-worker.js
chrome.scripting
.updateContentScripts([{
id: "session-script",
excludeMatches: ["*://admin.example.com/*"],
}])
.then(() => console.log("registration updated"));
service-worker.js
chrome.scripting
.getRegisteredContentScripts()
.then(scripts => console.log("registered content scripts", scripts));
service-worker.js
chrome.scripting
.unregisterContentScripts({ ids: ["session-script"] })
.then(() => console.log("un-registration complete"));
แทรกแบบเป็นโปรแกรม
ใช้การแทรกแบบเป็นโปรแกรมสำหรับสคริปต์เนื้อหาที่ต้องทำงานเพื่อตอบสนองต่อเหตุการณ์หรือในโอกาสที่เฉพาะเจาะจง
หากต้องการแทรกสคริปต์เนื้อหาแบบเป็นโปรแกรม ส่วนขยายต้องมีสิทธิ์โฮสต์สําหรับหน้าเว็บที่พยายามแทรกสคริปต์ สิทธิ์ของโฮสต์จะมอบให้ได้โดยขอสิทธิ์เหล่านั้นเป็นส่วนหนึ่งของไฟล์ Manifest ของส่วนขยาย หรือใช้ "activeTab"
ชั่วคราว
ต่อไปนี้คือส่วนขยายที่ใช้ activeTab เวอร์ชันต่างๆ
manifest.json:
{
"name": "My extension",
...
"permissions": [
"activeTab",
"scripting"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Action Button"
}
}
สคริปต์เนื้อหาสามารถแทรกเป็นไฟล์ได้
content-script.js
document.body.style.backgroundColor = "orange";
service-worker.js:
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target: { tabId: tab.id },
files: ["content-script.js"]
});
});
หรือจะแทรกและเรียกใช้เนื้อหาของฟังก์ชันเป็นสคริปต์เนื้อหาก็ได้
service-worker.js:
function injectedFunction() {
document.body.style.backgroundColor = "orange";
}
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target : {tabId : tab.id},
func : injectedFunction,
});
});
โปรดทราบว่าฟังก์ชันที่แทรกคือสําเนาของฟังก์ชันที่อ้างอิงในchrome.scripting.executeScript()
การเรียกใช้ ไม่ใช่ฟังก์ชันเดิม ด้วยเหตุนี้ เนื้อหาของฟังก์ชันจึงต้องอยู่ภายในตัวฟังก์ชันเอง การอ้างอิงตัวแปรภายนอกฟังก์ชันจะทำให้สคริปต์เนื้อหาแสดง ReferenceError
เมื่อแทรกเป็นฟังก์ชัน คุณจะส่งอาร์กิวเมนต์ไปยังฟังก์ชันได้ด้วย
service-worker.js
function injectedFunction(color) {
document.body.style.backgroundColor = color;
}
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target : {tabId : tab.id},
func : injectedFunction,
args : [ "orange" ],
});
});
ยกเว้นการจับคู่และนิพจน์ทั่วไป
หากต้องการปรับแต่งการจับคู่หน้าเว็บที่ระบุ ให้ใส่ฟิลด์ต่อไปนี้ในการลงทะเบียนแบบประกาศ
ชื่อ | ประเภท | คำอธิบาย |
---|---|---|
exclude_matches |
อาร์เรย์สตริง | ไม่บังคับ ยกเว้นหน้าที่สคริปต์เนื้อหานี้จะแทรกเข้าไป ดูรายละเอียดเกี่ยวกับไวยากรณ์ของสตริงเหล่านี้ได้ที่รูปแบบการจับคู่ |
include_globs |
อาร์เรย์สตริง | ไม่บังคับ ใช้หลังจาก matches เพื่อรวมเฉพาะ URL ที่ตรงกับนิพจน์ทั่วไปนี้ด้วย การดำเนินการนี้มีไว้เพื่อเลียนแบบคีย์เวิร์ด @include ใน Greasemonkey |
exclude_globs |
อาร์เรย์สตริง | ไม่บังคับ ใช้หลังจาก matches เพื่อยกเว้น URL ที่ตรงกับนิพจน์ทั่วไปนี้ มีไว้เพื่อเลียนแบบคีย์เวิร์ด @exclude ใน Greasemonkey |
ระบบจะแทรกสคริปต์เนื้อหาลงในหน้าเว็บหากทั้ง 2 เงื่อนไขต่อไปนี้เป็นจริง
- URL ของรายการดังกล่าวจะตรงกับรูปแบบ
matches
และinclude_globs
รูปแบบใดก็ได้ - นอกจากนี้ URL ยังไม่ตรงกับรูปแบบ
exclude_matches
หรือexclude_globs
ด้วย เนื่องจากต้องใช้พร็อพเพอร์ตี้matches
คุณจึงใช้exclude_matches
,include_globs
และexclude_globs
เพื่อจํากัดหน้าที่ได้รับผลกระทบได้เท่านั้น
ส่วนขยายต่อไปนี้จะแทรกสคริปต์เนื้อหาลงใน https://www.nytimes.com/health
แต่จะไม่แทรกลงใน https://www.nytimes.com/business
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.nytimes.com/*"],
"exclude_matches": ["*://*/*business*"],
"js": ["contentScript.js"]
}
],
...
}
service-worker.js
chrome.scripting.registerContentScripts([{
id : "test",
matches : [ "https://*.nytimes.com/*" ],
excludeMatches : [ "*://*/*business*" ],
js : [ "contentScript.js" ],
}]);
พร็อพเพอร์ตี้ Glob ใช้ไวยากรณ์ที่ยืดหยุ่นกว่ารูปแบบการทำงานของคีย์เวิร์ด สตริงที่ยอมรับคือ URL ที่อาจมีเครื่องหมายดอกจันและเครื่องหมายคําถาม "ไวลด์การ์ด" เครื่องหมายดอกจัน (*
) จะจับคู่กับสตริงที่มีความยาวเท่าใดก็ได้ รวมถึงสตริงว่าง ส่วนเครื่องหมายคําถาม (?
) จะจับคู่กับอักขระเดี่ยวตัวใดก็ได้
เช่น รูปแบบทั่วไป https://???.example.com/foo/\*
จะจับคู่กับรายการต่อไปนี้
https://www.example.com/foo/bar
https://the.example.com/foo/
แต่ไม่ตรงกับรายการต่อไปนี้
https://my.example.com/foo/bar
https://example.com/foo/
https://www.example.com/foo
ส่วนขยายนี้จะแทรกสคริปต์เนื้อหาลงใน https://www.nytimes.com/arts/index.html
และ https://www.nytimes.com/jobs/index.htm*
แต่ไม่แทรกลงใน https://www.nytimes.com/sports/index.html
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.nytimes.com/*"],
"include_globs": ["*nytimes.com/???s/*"],
"js": ["contentScript.js"]
}
],
...
}
ส่วนขยายนี้จะแทรกสคริปต์เนื้อหาลงใน https://history.nytimes.com
และ https://.nytimes.com/history
แต่ไม่แทรกลงใน https://science.nytimes.com
หรือ https://www.nytimes.com/science
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.nytimes.com/*"],
"exclude_globs": ["*science*"],
"js": ["contentScript.js"]
}
],
...
}
คุณรวมรายการเหล่านี้อย่างใดอย่างหนึ่ง ทั้งหมด หรือบางส่วนก็ได้เพื่อให้ได้ขอบเขตที่ถูกต้อง
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.nytimes.com/*"],
"exclude_matches": ["*://*/*business*"],
"include_globs": ["*nytimes.com/???s/*"],
"exclude_globs": ["*science*"],
"js": ["contentScript.js"]
}
],
...
}
เวลาทำงาน
ช่อง run_at
จะควบคุมเวลาที่ระบบจะแทรกไฟล์ JavaScript ลงในหน้าเว็บ ค่าที่แนะนำและค่าเริ่มต้นคือ "document_idle"
ดูค่าอื่นๆ ที่เป็นไปได้สำหรับประเภท RunAt
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.nytimes.com/*"],
"run_at": "document_idle",
"js": ["contentScript.js"]
}
],
...
}
service-worker.js
chrome.scripting.registerContentScripts([{
id : "test",
matches : [ "https://*.nytimes.com/*" ],
runAt : "document_idle",
js : [ "contentScript.js" ],
}]);
ชื่อ | ประเภท | คำอธิบาย |
---|---|---|
document_idle |
สตริง | แนะนำ ใช้ "document_idle" เมื่อเป็นไปได้เบราว์เซอร์จะเลือกเวลาเพื่อแทรกสคริปต์ระหว่าง "document_end" กับทันทีหลังจากเหตุการณ์ window.onload เริ่มต้น เวลาที่แน่นอนของอินเจคชั่นจะขึ้นอยู่กับความซับซ้อนของเอกสารและระยะเวลาในการโหลด และได้รับการเพิ่มประสิทธิภาพเพื่อความเร็วในการโหลดหน้าเว็บสคริปต์เนื้อหาที่ทำงานที่ "document_idle" ไม่จำเป็นต้องรอเหตุการณ์ window.onload เนื่องจากระบบรับประกันว่าสคริปต์จะทำงานหลังจาก DOM เสร็จสมบูรณ์ หากสคริปต์ต้องทำงานหลังจาก window.onload อย่างแน่นอน ส่วนขยายจะตรวจสอบได้ว่า onload เริ่มทํางานแล้วหรือยังโดยใช้พร็อพเพอร์ตี้ document.readyState |
document_start |
สตริง | ระบบจะแทรกสคริปต์หลังจากไฟล์จาก css แต่ก่อนสร้าง DOM อื่นๆ หรือเรียกใช้สคริปต์อื่นๆ |
document_end |
สตริง | ระบบจะแทรกสคริปต์ทันทีหลังจากที่ DOM เสร็จสมบูรณ์ แต่ก่อนที่ทรัพยากรย่อย เช่น รูปภาพและเฟรมจะโหลด |
ระบุเฟรม
สําหรับสคริปต์เนื้อหาแบบประกาศที่ระบุไว้ในไฟล์ Manifest ช่อง "all_frames"
ช่วยให้ส่วนขยายระบุได้ว่าควรแทรกไฟล์ JavaScript และ CSS ลงในเฟรมทั้งหมดที่ตรงกับข้อกําหนดของ URL ที่ระบุ หรือแทรกลงในเฟรมบนสุดในแท็บเท่านั้น
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.nytimes.com/*"],
"all_frames": true,
"js": ["contentScript.js"]
}
],
...
}
เมื่อลงทะเบียนสคริปต์เนื้อหาโดยใช้ chrome.scripting.registerContentScripts(...)
แบบเป็นโปรแกรม คุณสามารถใช้พารามิเตอร์ allFrames
เพื่อระบุว่าควรแทรกสคริปต์เนื้อหาลงในเฟรมทั้งหมดที่ตรงกับข้อกําหนดของ URL ที่ระบุ หรือเฉพาะในเฟรมบนสุดในแท็บ สามารถใช้กับ tabId เท่านั้น และใช้ไม่ได้หากระบุ frameIds หรือ documentIds
service-worker.js
chrome.scripting.registerContentScripts([{
id: "test",
matches : [ "https://*.nytimes.com/*" ],
allFrames : true,
js : [ "contentScript.js" ],
}]);
แทรกลงในเฟรมที่เกี่ยวข้อง
ชิ้นงานอาจต้องการเรียกใช้สคริปต์ในเฟรมที่เกี่ยวข้องกับเฟรมที่ตรงกัน แต่ตัวชิ้นงานเองไม่ได้ตรงกัน สถานการณ์ที่พบบ่อยในกรณีนี้คือเฟรมที่มี URL ที่สร้างขึ้นโดยเฟรมที่ตรงกัน แต่ URL ของเฟรมนั้นไม่ตรงกับรูปแบบที่ระบุของสคริปต์
กรณีนี้เกิดขึ้นเมื่อส่วนขยายต้องการแทรกลงในเฟรมที่มี URL ที่ใช้รูปแบบ about:
, data:
, blob:
และ filesystem:
ในกรณีเหล่านี้ URL จะไม่ตรงกับรูปแบบของสคริปต์เนื้อหา (และในกรณีของ about:
และ data:
จะไม่รวม URL หลักหรือต้นทางใน URL เลย เช่น ใน about:blank
หรือ data:text/html,<html>Hello, World!</html>
) แต่เฟรมเหล่านี้จะยังคงเชื่อมโยงกับเฟรมที่สร้างได้
หากต้องการแทรกลงในเฟรมเหล่านี้ ส่วนขยายสามารถระบุพร็อพเพอร์ตี้ "match_origin_as_fallback"
ในข้อกําหนดของสคริปต์เนื้อหาในไฟล์ Manifest
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.google.com/*"],
"match_origin_as_fallback": true,
"js": ["contentScript.js"]
}
],
...
}
เมื่อระบุและตั้งค่าเป็น true
แล้ว Chrome จะดูที่ต้นทางของเงื่อนไขเริ่มต้นของเฟรมเพื่อพิจารณาว่าเฟรมนั้นตรงกันหรือไม่ แทนที่จะดูที่ URL ของเฟรม โปรดทราบว่าค่านี้อาจแตกต่างจากต้นทางของเฟรมเป้าหมายด้วย (เช่น URL data:
มีต้นทางเป็นค่าว่าง)
ต้นทางของเฟรมคือเฟรมที่สร้างหรือไปยังเฟรมเป้าหมาย แม้ว่าโดยทั่วไปจะเป็นหน้าหลักหรือหน้าเปิดโดยตรง แต่ก็ไม่ได้เป็นเช่นนั้นเสมอไป (เช่น ในกรณีที่เฟรมไปยัง iframe ภายใน iframe)
เนื่องจากข้อมูลนี้เปรียบเทียบต้นทางของเฟรมเริ่มต้น เฟรมเริ่มต้นจึงอาจอยู่ในเส้นทางใดก็ได้จากต้นทางนั้น เพื่อให้เห็นภาพชัดเจนขึ้น Chrome จะกำหนดให้สคริปต์เนื้อหาที่ระบุด้วย "match_origin_as_fallback"
ที่มีค่าเป็น true
ต้องระบุเส้นทางของ *
ด้วย
เมื่อระบุทั้ง "match_origin_as_fallback"
และ "match_about_blank"
"match_origin_as_fallback"
จะมีลำดับความสำคัญเหนือกว่า
การสื่อสารกับหน้าการฝัง
แม้ว่าสภาพแวดล้อมการเรียกใช้ของสคริปต์เนื้อหาและหน้าเว็บที่โฮสต์สคริปต์จะแยกจากกัน แต่สคริปต์และหน้าเว็บก็แชร์สิทธิ์เข้าถึง DOM ของหน้าเว็บ หากหน้าเว็บต้องการสื่อสารกับสคริปต์เนื้อหาหรือกับส่วนขยายผ่านสคริปต์เนื้อหา จะต้องดำเนินการผ่าน DOM ที่แชร์
ตัวอย่างการใช้ window.postMessage()
content-script.js
var port = chrome.runtime.connect();
window.addEventListener("message", (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);
example.js
document.getElementById("theButton").addEventListener("click", () => {
window.postMessage(
{type : "FROM_PAGE", text : "Hello from the webpage!"}, "*");
}, false);
หน้าเว็บที่ไม่ใช่ส่วนขยาย example.html จะโพสต์ข้อความไปยังตัวเอง สคริปต์เนื้อหาจะขัดจังหวะและตรวจสอบข้อความนี้ จากนั้นจึงส่งไปยังกระบวนการขยาย วิธีนี้ช่วยให้หน้าเว็บมีช่องทางการสื่อสารกับกระบวนการขยายเวลา การดำเนินการย้อนกลับทำได้ด้วยวิธีเดียวกัน
เข้าถึงไฟล์ส่วนขยาย
หากต้องการเข้าถึงไฟล์ส่วนขยายจากสคริปต์เนื้อหา คุณสามารถเรียกใช้ chrome.runtime.getURL()
เพื่อรับ URL แบบสัมบูรณ์ของชิ้นงานส่วนขยาย ดังที่แสดงในตัวอย่างต่อไปนี้ (content.js
)
content-script.js
let image = chrome.runtime.getURL("images/my_image.png")
หากต้องการใช้แบบอักษรหรือรูปภาพในไฟล์ CSS คุณสามารถใช้ @@extension_id
เพื่อสร้าง URL ดังที่แสดงในตัวอย่างต่อไปนี้ (content.css
)
content.css
body {
background-image:url('chrome-extension://__MSG_@@extension_id__/background.png');
}
@font-face {
font-family: 'Stint Ultra Expanded';
font-style: normal;
font-weight: 400;
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Stint Ultra Expanded.woff') format('woff');
}
ชิ้นงานทั้งหมดต้องได้รับการประกาศเป็นแหล่งข้อมูลที่เข้าถึงได้ทางเว็บในไฟล์ manifest.json
manifest.json
{
...
"web_accessible_resources": [
{
"resources": [ "images/*.png" ],
"matches": [ "https://example.com/*" ]
},
{
"resources": [ "fonts/*.woff" ],
"matches": [ "https://example.com/*" ]
}
],
...
}
รักษาความปลอดภัย
แม้ว่าโลกที่แยกต่างหากจะมอบการป้องกันอีกชั้นหนึ่ง แต่การใช้สคริปต์เนื้อหาอาจสร้างช่องโหว่ในส่วนขยายและหน้าเว็บ หากสคริปต์เนื้อหารับเนื้อหาจากเว็บไซต์อื่น เช่น การเรียกใช้ fetch()
ให้ระมัดระวังในการกรองเนื้อหาเพื่อป้องกันการโจมตีด้วยสคริปต์ข้ามเว็บไซต์ก่อนที่จะแทรกเนื้อหา สื่อสารผ่าน HTTPS เท่านั้นเพื่อหลีกเลี่ยงการโจมตี"man-in-the-middle"
อย่าลืมกรองหาหน้าเว็บที่เป็นอันตราย ตัวอย่างเช่น รูปแบบต่อไปนี้เป็นรูปแบบที่เป็นอันตรายและไม่อนุญาตใน Manifest V3
content-script.js
const data = document.getElementById("json-data"); // WARNING! Might be evaluating an evil script! const parsed = eval("(" + data + ")");
content-script.js
const elmt_id = ... // WARNING! elmt_id might be '); ... evil script ... //'! window.setTimeout("animate(" + elmt_id + ")", 200);
แต่ให้ใช้ API ที่ปลอดภัยกว่าซึ่งไม่เรียกใช้สคริปต์แทน
content-script.js
const data = document.getElementById("json-data") // JSON.parse does not evaluate the attacker's scripts. const parsed = JSON.parse(data);
content-script.js
const elmt_id = ... // The closure form of setTimeout does not evaluate scripts. window.setTimeout(() => animate(elmt_id), 200);