สคริปต์เนื้อหาเป็นไฟล์ที่ทำงานในบริบทของหน้าเว็บ การใช้เอกสารมาตรฐาน 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);
การเปลี่ยนแปลงนี้จะทำให้การแจ้งเตือนทั้งสองแสดงตามลำดับเมื่อคลิกปุ่ม
แทรกสคริปต์
สคริปต์เนื้อหาสามารถประกาศแบบคงที่ ประกาศ แบบไดนามิกหรือการแทรกแบบเป็นโปรแกรม
แทรกการประกาศแบบคงที่
ใช้การประกาศสคริปต์เนื้อหาแบบคงที่ในไฟล์ 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 |
อาร์เรย์ของสตริง | ต้องระบุ ระบุหน้าที่จะแทรกสคริปต์เนื้อหานี้ ดูรูปแบบการจับคู่สำหรับรายละเอียดเกี่ยวกับไวยากรณ์ของสตริงเหล่านี้ และจับคู่รูปแบบและ globs สำหรับข้อมูลเกี่ยวกับวิธียกเว้น URL |
css |
อาร์เรย์ของสตริง | ไม่บังคับ รายการไฟล์ CSS ที่จะแทรกลงในหน้าที่ตรงกัน สิ่งเหล่านี้คือ แทรกตามลำดับที่ปรากฏในอาร์เรย์นี้ ก่อนที่จะมีการสร้างหรือแสดง DOM สำหรับหน้านั้น |
js |
|
ไม่บังคับ รายการไฟล์ JavaScript ที่จะแทรกลงในหน้าที่ตรงกัน ไฟล์ จะถูกแทรกตามลำดับที่ปรากฏในอาร์เรย์นี้ แต่ละสตริงในรายการนี้ต้องมี เส้นทางแบบสัมพัทธ์ไปยังทรัพยากรในไดเรกทอรีรากของส่วนขยาย เครื่องหมายทับ ("/") คือ จะตัดโดยอัตโนมัติ |
run_at |
RunAt | ไม่บังคับ ระบุเวลาที่ควรแทรกสคริปต์ลงในหน้าเว็บ ค่าเริ่มต้นคือ
document_idle |
match_about_blank |
boolean | ไม่บังคับ สคริปต์ควรแทรกลงในเฟรม about:blank หรือไม่
โดยที่เฟรมระดับบนสุดหรือเฟรมแบบเปิดตรงกับรูปแบบที่ประกาศไว้ใน
matches ค่าเริ่มต้นคือ "เท็จ" |
match_origin_as_fallback |
boolean |
ไม่บังคับ สคริปต์ควรแทรกในเฟรมที่
สร้างโดยต้นทางที่ตรงกัน แต่ 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"
ชั่วคราว
ต่อไปนี้เป็นเวอร์ชันต่างๆ ของส่วนขยายที่ใช้แท็บแอ็กทีฟ
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" ],
});
});
ไม่รวมการแข่งขันและ glob
หากต้องการปรับแต่งการจับคู่หน้าที่ระบุ ให้ใส่ฟิลด์ต่อไปนี้ในการประกาศ การลงทะเบียน
ชื่อ | ประเภท | คำอธิบาย |
---|---|---|
exclude_matches |
อาร์เรย์ของสตริง | ไม่บังคับ ยกเว้นหน้าที่มีการแทรกสคริปต์เนื้อหานี้ เข้าไปด้วย โปรดดูที่รูปแบบการจับคู่สำหรับรายละเอียดเกี่ยวกับไวยากรณ์ของ สตริงเหล่านี้ |
include_globs |
อาร์เรย์ของสตริง | ไม่บังคับ ใช้หลังวันที่ matches เพื่อรวมเฉพาะ URL ที่
ตรงกับโลกนี้ ส่วนนี้มีไว้เพื่อจำลอง @include
คีย์เวิร์ด Greasemonkey |
exclude_globs |
อาร์เรย์ของสตริง | ไม่บังคับ ใช้หลังวันที่ matches เพื่อยกเว้น URL ที่ตรงกับรายการนี้
glob ตั้งใจที่จะจำลอง@exclude
คีย์เวิร์ด Greasemonkey |
ระบบจะแทรกสคริปต์เนื้อหาลงในหน้าเว็บหากเงื่อนไขทั้ง 2 ข้อต่อไปนี้เป็นจริง
- URL ของ 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 มีไวยากรณ์ที่ยืดหยุ่นและแตกต่างจากรูปแบบการจับคู่ glob ที่ยอมรับ
สตริงคือ URL ที่อาจมี "ไวลด์การ์ด" เครื่องหมายดอกจันและเครื่องหมายคำถาม เครื่องหมายดอกจัน (*
)
จะจับคู่สตริงใดก็ได้ที่มีความยาว รวมทั้งสตริงว่าง ขณะที่เครื่องหมายคำถาม (?
) จะจับคู่
อักขระเดี่ยวๆ
ตัวอย่างเช่น glob 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 เสร็จสมบูรณ์ แต่ก่อนทรัพยากรย่อย เช่น โหลดรูปภาพและเฟรมแล้ว |
ระบุเฟรม
ช่อง "all_frames"
ช่วยให้ส่วนขยายระบุได้ว่าควรแนบไฟล์ JavaScript และ CSS หรือไม่
แทรกลงในเฟรมทั้งหมดที่ตรงกับข้อกำหนดของ URL ที่ระบุ หรือเฉพาะในเฟรมระดับบนสุดใน
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.nytimes.com/*"],
"all_frames": true,
"js": ["contentScript.js"]
}
],
...
}
service-worker.js
chrome.scripting.registerContentScripts([{
id: "test",
matches : [ "https://*.nytimes.com/*" ],
allFrames : true,
js : [ "contentScript.js" ],
}]);
ชื่อ | ประเภท | คำอธิบาย |
---|---|---|
all_frames |
boolean | ไม่บังคับ ค่าเริ่มต้นคือ false ซึ่งหมายความว่าเฉพาะเฟรมด้านบนเท่านั้น
ตรงกันหากระบุ true ไว้ ระบบจะแทรกเฟรมทั้งหมดลงใน
เฟรมไม่ใช่เฟรมบนสุดในแท็บ ระบบจะตรวจสอบ URL แต่ละเฟรมแยกกัน
โดยจะไม่แทรกลงในเฟรมย่อยหากไม่เป็นไปตามข้อกำหนดของ URL |
แทรกลงในเฟรมที่เกี่ยวข้อง
ส่วนขยายอาจต้องเรียกใช้สคริปต์ในเฟรมที่เกี่ยวข้องกับการจับคู่ที่ตรงกัน เฟรมแต่ไม่ตรงให้กับตัวเอง กรณีทั่วไปในกรณีนี้คือ สำหรับเฟรมที่มี 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:
รายการมีต้นทางเป็น Null)
จุดเริ่มของเฟรมคือเฟรมที่สร้างหรือนำทางเป้าหมาย เฟรม แม้ว่าโดยทั่วไปจะเป็นรายการระดับบนโดยตรงหรือเงื่อนไขเริ่มต้น แต่ก็อาจไม่ใช่ (เช่น ในกรณีที่เฟรมนำทาง 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()
โปรดระมัดระวังเพื่อกรองเนื้อหา
การโจมตี cross-site Scripting ก่อนแทรกสคริปต์ สื่อสารผ่าน 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);