콘텐츠 스크립트는 확장이 아닌 웹 페이지의 컨텍스트에서 실행되기 때문에 종종 나머지 확장과 통신하는 방법이 필요합니다.
예를 들어 RSS 리더 확장은 콘텐츠 스크립트를 사용하여 페이지에서 RSS 피드의 존재를 감지 한 다음 해당 페이지에 대한 페이지 작업 아이콘을 표시하기 위해 배경 페이지에 알릴 수 있습니다.
확장 프로그램과 해당 콘텐츠 스크립트 간의 통신은 메시지 전달을 사용하여 작동합니다. 양쪽 모두 다른 쪽에서 보낸 메시지를 수신하고 동일한 채널에서 응답 할 수 있습니다. 메시지에는 유효한 JSON 개체 (null, 부울, 숫자, 문자열, 배열 또는 개체)가 포함될 수 있습니다. 일회성 요청을 위한 간단한 API와 공유 컨텍스트로 여러 메시지를 교환하기 위한 장기 연결을 허용하는 더 복잡한 API가 있습니다. 교차 확장 메시지 섹션에서 다룬 ID를 알고 있는 경우 다른 확장에 메시지를 보낼 수도 있습니다.
간단한 일회성 요청
확장의 다른 부분에 단일 메시지 만 보내야 하는 경우 (선택적으로 응답을 다시 받을 수 있음) 단순화 된 runtime.sendMessage 또는 tabs.sendMessage를 사용해야 합니다. 이를 통해 콘텐츠 스크립트에서 확장 프로그램으로 또는 그 반대로 각각 JSON 직렬화 가능한 일회성 메시지를 보낼 수 있습니다. 선택적인 콜백 매개 변수를 사용하면 다른 쪽의 응답을 처리 할 수 있습니다.
콘텐츠 스크립트에서 요청을 보내는 것은 다음과 같습니다.
chrome.runtime.sendMessage({greeting: "hello"}, function(response) { console.log(response.farewell); });
확장에서 콘텐츠 스크립트로 요청을 보내는 것은 보낼 탭을 지정해야 한다는 점을 제외하면 매우 유사합니다. 이 예는 선택한 탭의 콘텐츠 스크립트에 메시지를 보내는 방법을 보여줍니다.
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) { console.log(response.farewell); }); });
수신 측에서 메시지를 처리하기 위해 runtime.onMessage 이벤트 리스너를 설정해야 합니다. 이것은 콘텐츠 스크립트 또는 확장 페이지에서 동일하게 보입니다.
chrome.runtime.onMessage.addListener( function(request, sender, sendResponse) { console.log(sender.tab ? "from a content script:" + sender.tab.url : "from the extension"); if (request.greeting == "hello") sendResponse({farewell: "goodbye"}); });
위의 예에서 sendResponse는 동 기적으로 호출되었습니다. 비동기 적으로 sendResponse를 사용하려면 return true를 추가하십시오. onMessage 이벤트 핸들러에.
참고 : 여러 페이지가 onMessage 이벤트를 수신하는 경우 특정 이벤트에 대해 sendResponse()를 처음 호출 한 사람 만 응답 전송에 성공합니다. 해당 이벤트에 대한 다른 모든 응답은 무시됩니다.
참고 : sendResponse 콜백은 동 기적으로 사용되거나 이벤트 핸들러가 비동기 적으로 응답 할 것임을 나타 내기 위해 true를 반환하는 경우에만 유효합니다. true를 반환하는 핸들러가 없거나 sendResponse 콜백이 가비지 수집 된 경우 sendMessage 함수의 콜백이 자동으로 호출됩니다.
수명이 긴 연결
때로는 단일 요청 및 응답보다 오래 지속되는 대화를 갖는 것이 유용합니다. 이 경우에는 각각 runtime.connect 또는 tabs.connect를 사용하여 콘텐츠 스크립트에서 확장 프로그램 페이지로 또는 그 반대로 수명이 긴 채널을 열 수 있습니다. 채널은 선택적으로 이름을 가질 수 있으므로 다른 유형의 연결을 구별 할 수 있습니다.
한 가지 사용 사례는 자동 양식 채우기 확장 일 수 있습니다. 콘텐츠 스크립트는 특정 로그인을 위해 확장 페이지에 대한 채널을 열고 페이지의 각 입력 요소에 대한 확장에 메시지를 보내서 채울 양식 데이터를 요청할 수 있습니다. 공유 연결을 사용하면 확장이 공유 상태 링크를 유지할 수 있습니다. 콘텐츠 스크립트에서 오는 여러 메시지.
연결을 설정할 때 각 끝에는 해당 연결을 통해 메시지를 보내고 받는 데 사용되는 runtime.Port 개체가 제공됩니다.
다음은 콘텐츠 스크립트에서 채널을 열고 메시지를 보내고 수신하는 방법입니다.
var port = chrome.runtime.connect({name: "knockknock"}); port.postMessage({joke: "Knock knock"}); port.onMessage.addListener(function(msg) { if (msg.question == "Who's there?") port.postMessage({answer: "Madame"}); else if (msg.question == "Madame who?") port.postMessage({answer: "Madame... Bovary"}); });
확장에서 콘텐츠 스크립트로 요청을 보내는 것은 연결할 탭을 지정해야 한다는 점을 제외하면 매우 유사합니다. 위의 예에서 연결 호출을 tabs.connect로 바꾸면 됩니다.
들어오는 연결을 처리하려면 runtime.onConnect 이벤트 리스너를 설정해야 합니다. 이는 콘텐츠 스크립트 또는 확장 페이지에서 동일하게 보입니다. 확장의 다른 부분이 "connect()"를 호출하면 연결을 통해 메시지를 보내고 받는 데 사용할 수 있는 runtime.Port 개체와 함께 이 이벤트가 시작됩니다. 들어오는 연결에 응답하는 모습은 다음과 같습니다.
chrome.runtime.onConnect.addListener(function(port) { console.assert(port.name == "knockknock"); port.onMessage.addListener(function(msg) { if (msg.joke == "Knock knock") port.postMessage({question: "Who's there?"}); else if (msg.answer == "Madame") port.postMessage({question: "Madame who?"}); else if (msg.answer == "Madame... Bovary") port.postMessage({question: "I don't get it."}); }); });
Port lifetime
포트는 확장의 서로 다른 부분 간의 양방향 통신 방법으로 설계되었으며, 여기서 (최상위 수준) 프레임은 가장 작은 부분으로 간주됩니다. tabs.connect, runtime.connect 또는 runtime.connectNative를 호출하면 포트가 생성됩니다. 이 포트는 postMessage를 통해 다른 쪽 끝으로 메시지를 보내는 데 즉시 사용할 수 있습니다.
탭에 여러 프레임이 있는 경우 tabs.connect를 호출하면 runtime.onConnect 이벤트가 여러 번 호출됩니다 (탭의 각 프레임에 대해 한 번씩). 마찬가지로 runtime.connect를 사용하면 onConnect 이벤트가 여러 번 실행될 수 있습니다 (확장 프로세스의 모든 프레임에 대해 한 번).
예를 들어 열려있는 각 포트에 대해 별도의 상태를 유지하고 있는지 여부와 같이 연결이 닫혀 있는 시기를 확인할 수 있습니다. 이를 위해 runtime.Port.onDisconnect 이벤트를 수신 할 수 있습니다. 이 이벤트는 채널의 다른 쪽에 유효한 포트가 없을 때 시작됩니다. 이것은 다음 상황에서 발생합니다.
교차 확장 메시징
확장 프로그램의 다른 구성 요소 간에 메시지를 보내는 것 외에도 메시징 API를 사용하여 다른 확장 프로그램과 통신 할 수 있습니다. 이를 통해 다른 확장에서 활용할 수 있는 공용 API를 노출 할 수 있습니다.
들어오는 요청 및 연결을 수신하는 것은 runtime.onMessageExternal 또는 runtime.onConnectExternal 메서드를 사용한다는 점을 제외하면 내부 사례와 유사합니다. 다음은 각각의 예입니다.
// For simple requests: chrome.runtime.onMessageExternal.addListener( function(request, sender, sendResponse) { if (sender.id == blocklistedExtension) return; // don't allow this extension access else if (request.getTargetData) sendResponse({targetData: targetData}); else if (request.activateLasers) { var success = activateLasers(); sendResponse({activateLasers: success}); } }); // For long-lived connections: chrome.runtime.onConnectExternal.addListener(function(port) { port.onMessage.addListener(function(msg) { // See other examples for sample onMessage handlers. }); });
마찬가지로 다른 내선 번호로 메시지를 보내는 것은 내선 번호 내에서 메시지를 보내는 것과 비슷합니다. 유일한 차이점은 통신하려는 내선 번호의 ID를 전달해야 한다는 것입니다. 예를 들면 :
// The ID of the extension we want to talk to. var laserExtensionId = "abcdefghijklmnoabcdefhijklmnoabc"; // Make a simple request: chrome.runtime.sendMessage(laserExtensionId, {getTargetData: true}, function(response) { if (targetInRange(response.targetData)) chrome.runtime.sendMessage(laserExtensionId, {activateLasers: true}); }); // Start a long-running conversation: var port = chrome.runtime.connect(laserExtensionId); port.postMessage(...);
웹 페이지에서 메시지 보내기
교차 확장 메시징과 유사하게 앱 또는 확장 프로그램은 일반 웹 페이지에서 메시지를 수신하고 응답 할 수 있습니다. 이 기능을 사용하려면 먼저 manifest.json에서 통신 할 웹 사이트를 지정해야 합니다. 예를 들면 :
"externally_connectable": { "matches": ["*://*.example.com/*"] }
이렇게 하면 지정한 URL 패턴과 일치하는 모든 페이지에 메시징 API가 노출됩니다. URL 패턴은 최소한 2 단계 도메인을 포함해야 합니다. 즉, "*", "* .com", "* .co.uk"및 "* .appspot.com"과 같은 호스트 이름 패턴은 금지됩니다. 웹 페이지에서 runtime.sendMessage 또는 runtime.connect API를 사용하여 특정 앱 또는 확장 프로그램에 메시지를 보냅니다. 예를 들면 :
// The ID of the extension we want to talk to. var editorExtensionId = "abcdefghijklmnoabcdefhijklmnoabc"; // Make a simple request: chrome.runtime.sendMessage(editorExtensionId, {openUrlInEditor: url}, function(response) { if (!response.success) handleError(url); });
앱 또는 확장 프로그램에서 교차 확장 메시징과 유사한 runtime.onMessageExternal 또는 runtime.onConnectExternal API를 통해 웹 페이지의 메시지를 수신 할 수 있습니다. 웹 페이지 만 연결을 시작할 수 있습니다. 다음은 그 예입니다.
chrome.runtime.onMessageExternal.addListener( function(request, sender, sendResponse) { if (sender.url == blocklistedWebsite) return; // don't allow this web page access if (request.openUrlInEditor) openUrl(request.openUrlInEditor); });
네이티브 메시징
확장 프로그램 및 앱은 네이티브 메시징 호스트로 등록 된 네이티브 애플리케이션과 메시지를 교환 할 수 있습니다. 이 기능에 대해 자세히 알아 보려면 기본 메시징을 참조하십시오.
보안 고려 사항
콘텐츠 스크립트의 신뢰성이 떨어짐
콘텐츠 스크립트는 확장 백그라운드 페이지보다 덜 신뢰할 수 있습니다 (예 : 악성 웹 페이지가 콘텐츠 스크립트가 실행되는 렌더러 프로세스를 손상시킬 수 있음). 콘텐츠 스크립트의 메시지가 공격자가 만든 것일 수 있다고 가정하고 모든 입력을 확인하고 삭제해야 합니다. 콘텐츠 스크립트로 전송 된 데이터가 웹 페이지로 유출 될 수 있다고 가정합니다. 콘텐츠 스크립트에서 받은 메시지에 의해 트리거 될 수 있는 권한 있는 작업의 범위를 제한합니다.
Cross-site scripting
콘텐츠 스크립트 또는 다른 확장 프로그램에서 메시지를 받을 때 스크립트는 크로스 사이트 스크립팅의 희생양이 되지 않도록주의해야합니다. 이 조언은 확장 백그라운드 페이지 내에서 실행되는 스크립트와 다른 웹 오리진 내에서 실행되는 콘텐츠 스크립트에 적용됩니다. 특히 아래와 같은 위험한 API를 사용하지 마십시오.
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) { // WARNING! Might be evaluating an evil script! var resp = eval("(" + response.farewell + ")"); });
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) { // WARNING! Might be injecting a malicious script! document.getElementById("resp").innerHTML = response.farewell; });
대신 스크립트를 실행하지 않는 안전한 API를 선호하십시오.
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) { // JSON.parse does not evaluate the attacker's scripts. var resp = JSON.parse(response.farewell); });
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) { // innerText does not let the attacker inject HTML elements. document.getElementById("resp").innerText = response.farewell; });
예
examples/api/ messaging 디렉토리에서 메시지를 통한 간단한 커뮤니케이션 예제를 찾을 수 있습니다. 기본 메시징 샘플은 Chrome 앱이 기본 앱과 통신하는 방법을 보여줍니다. 더 많은 예제와 소스 코드 보기에 대한 도움말은 샘플을 참조하십시오.
등록된 댓글이 없습니다.