Content_scripts не могут получать сообщение сразу после установки webextension [duplicate]

Не говоря уже о том, что в будущем в будущем должны быть разрешены нелатинские (китайские, арабские, греческие, ивриты, кириллицы и т. д.) имена доменов. Каждый должен изменить используемое регулярное выражение электронной почты, потому что эти символы, несомненно, не будут покрываться [a-z]/i и \w. Все они потерпят неудачу.

В конце концов, лучший способ проверить адрес электронной почты по-прежнему на самом деле отправить письмо на адрес, о котором идет речь, для проверки адреса. Если адрес электронной почты является частью аутентификации пользователя (register / login / etc), вы можете идеально комбинировать его с системой активации пользователя. То есть отправьте электронное письмо со ссылкой с уникальным ключом активации на указанный адрес электронной почты и разрешите только регистрацию, когда пользователь активировал вновь созданную учетную запись, используя ссылку в письме.

Если целью регулярного выражения является просто для того, чтобы быстро сообщить пользователю в пользовательском интерфейсе, что указанный адрес электронной почты не выглядит в нужном формате, лучше всего проверить, соответствует ли оно в основном следующее регулярное выражение:

^([^.@]+)(\.[^.@]+)*@([^.@]+\.)+([^.@]+)$

, Почему бы вам не беспокоиться о персонажах, используемых в названии и домене? Клиент обязан ввести правильный адрес электронной почты, а не сервер. Даже когда клиент входит в синтаксически действительный адрес электронной почты, такой как aa@bb.cc, это не гарантирует, что это законный адрес электронной почты. Никакое регулярное выражение не может покрыть это.

13
задан Xan 27 May 2014 в 18:53
поделиться

2 ответа

Ваш скрипт не работает из-за того, как вставляются сценарии содержимого.

Проблема

Когда вы (повторно) загружаете расширение, вопреки ожиданиям некоторых людей, Chrome будет не добавлять сценарии содержания в существующие вкладки, которые соответствуют шаблонам из манифеста. Только после того, как расширение будет загружено, любая навигация будет проверять URL-адрес для сопоставления и будет вводить код.

Итак, временная шкала:

  1. Вы открываете некоторые вкладки. Нет сценариев содержимого.
  2. Вы загружаете расширение. Его код верхнего уровня запускается: он пытается передать сообщение на текущую вкладку.
  3. Поскольку там еще нет слушателя, он не работает. (Это, вероятно, страница chrome://extensions/, и вы все равно не можете вставлять туда)
  4. Если после этого вы попытаетесь перейти / открыть новую вкладку, слушатель будет введен, но ваш код верхнего уровня нет

1 - Это также происходит, если вы перезагрузите расширение. Если был введен сценарий содержимого, он продолжает обрабатывать свои события / не получает разгруженную, но больше не может связываться с расширением. (подробнее см. добавление в конце)

Решения

Решение 1: вы можете сначала спросить вкладку, по которой вы отправляете сообщение, готов ли он, и после молчания скрипт программно. Рассмотрим:

// Background
function ensureSendMessage(tabId, message, callback){
  chrome.tabs.sendMessage(tabId, {ping: true}, function(response){
    if(response && response.pong) { // Content script ready
      chrome.tabs.sendMessage(tabId, message, callback);
    } else { // No listener on the other end
      chrome.tabs.executeScript(tabId, {file: "content_script.js"}, function(){
        if(chrome.runtime.lastError) {
          console.error(chrome.runtime.lastError);
          throw Error("Unable to inject script into tab " + tabId);
        }
        // OK, now it's injected and ready
        chrome.tabs.sendMessage(tabId, message, callback);
      });
    }
  });
}

chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
  ensureSendMessage(tabs[0].id, {greeting: "hello"});
});

и

// Content script
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  if(request.ping) { sendResponse({pong: true}); return; }
  /* Content script action */
});

Решение 2: всегда вставляйте скрипт, но убедитесь, что он выполняется только один раз.

// Background
function ensureSendMessage(tabId, message, callback){
  chrome.tabs.executeScript(tabId, {file: "content_script.js"}, function(){
    if(chrome.runtime.lastError) {
      console.error(chrome.runtime.lastError);
      throw Error("Unable to inject script into tab " + tabId);
    }
    // OK, now it's injected and ready
    chrome.tabs.sendMessage(tabId, message, callback);
  });
}

и

// Content script
var injected;

if(!injected){
  injected = true;
  /* your toplevel code */
}

Это проще, но имеет сложности при перезагрузке. После того, как расширение будет перезагружено, старый скрипт все еще существует1, но он больше не «ваш» контекст, поэтому injected не будет определен. Остерегайтесь побочных эффектов потенциального выполнения вашего сценария дважды.


Решение 3: просто произвольно вводите скрипт (ы) контента при инициализации. Это можно сделать только в том случае, если безопасно запускать один и тот же сценарий содержимого дважды или запустить его после полной загрузки страницы.

chrome.tabs.query({}, function(tabs) {
  for(var i in tabs) {
    // Filter by url if needed; that would require "tabs" permission
    // Note that injection will simply fail for tabs that you don't have permissions for
    chrome.tabs.executeScript(tabs[i].id, {file: "content_script.js"}, function() {
      // Now you can use normal messaging
    });
  }
}); 

Я также подозреваю, что вы хотите, чтобы он работал некоторые действия, а не на нагрузку расширения. Например, вы можете использовать действие браузера и обернуть свой код в прослушиватель chrome.browserAction.onClicked.


Добавление к сценариям с сиротским контентом

Когда расширение будет перезагружено, можно ожидать, что Chrome очистит все сценарии контента. Но, по-видимому, это не так; слушатели контент-скриптов не отключены. Тем не менее, любая передача сообщений с родительским расширением не будет выполнена. Это, вероятно, следует считать ошибкой и в какой-то момент может быть исправлено. Я собираюсь назвать это состояние «потерянным»

. Это не проблема ни в одном из двух случаев :

  1. В контентном скрипте нет слушателей событий на странице (например, только один раз выполняется или прослушивается только сообщения из фона)
  2. Скрипт содержимого ничего не делает с страницы и только сообщения о событиях.

Однако, если это не так, у вас возникла проблема: скрипт содержимого может что-то делать, но не работает или не вмешивается в другой, сам по себе несигналированный экземпляр.

Решением этого будет:

  1. Следить за всеми прослушивателями событий, которые могут запускаться на странице
  2. . Перед тем, как действовать на эти события, отправьте сообщение " heartbeat "сообщение для фона. 3a. Если фон отвечает, мы хороши и должны выполнить действие. 3b. Если передача сообщения завершается с ошибкой, мы становимся сиротами и должны воздерживаться; игнорировать событие и отменять регистрацию всех слушателей.

Код, сценарий содержимого:

function heartbeat(success, failure) {
  chrome.runtime.sendMessage({heartbeat: true}, function(reply){
    if(chrome.runtime.lastError){
      failure();
    } else {
      success();
    }
  });
}

function handler() {
  heartbeat(
    function(){ // hearbeat success
      /* Do stuff */
    }, 
    function(){ // hearbeat failure
      someEvent.removeListener(handler);
      console.log("Goodbye, cruel world!");
    }
  );
}
someEvent.addListener(handler);

Фоновый скрипт:

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  if(request.heartbeat) { sendResponse(request); return; }
  /* ... */
});    
40
ответ дан Xan 23 August 2018 в 17:21
поделиться

В моем background.js

chrome.tabs.onUpdated.addListener(function(tabId, info, tab) {
  if (tab.url !== undefined && info.status == "complete") {

    chrome.tabs.query({active: true, currentWindow: true, status: "complete"}, function (tabs) {
      console.log(tabs);
      chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function (response) {
        console.log(response.farewell);
      });
    });
  }
});

Мой manifest.json

"content_scripts": [
{
  "matches": ["http://*/*", "https://*/*"],
  "js": [
    "content_script.js"
  ],
  "run_at": "document_end"
}

Мой «content_sciprt.js» работал после «background.js». поэтому я не могу получить ответ.

Но после того, как я добавил

  1. info.status=="complete", status: "complete"
  2. "run_at": "document_end" в своем манифесте .json

Он отлично работает

-1
ответ дан Zong 23 August 2018 в 17:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: