Я получаю эту ошибку снова и снова и до сих пор не могу понять, как ее решить. Функция sendResponse
вызывается до того, как функция analyzePageGuest
завершила свое выполнение, но я не могу это исправить. Проект, который я делаю, представляет собой расширение для обнаружения фишинга с использованием API Virus Total. Вот что я пробовал: Может ли кто-нибудь мне помочь?
фон.js
async function analyzePageGuest(tabId, changeInfo, tab) {
const url = tab.url
console.info('URL:', url)
let analysisIdValue
try {
const options = {
method: 'POST',
headers: {
accept: 'application/json',
'x-apikey':
'apikey',
'content-type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({ url: url }),
}
fetch(
'https://cors-anywhere.herokuapp.com/https://www.virustotal.com/api/v3/urls',
options
)
.then((response) => response.json())
.then((response) => {
console.info(response)
analysisIdValue = response.data.id
console.info(analysisIdValue)
})
.catch((err) => console.error(err))
// Wait for the analysis to complete using a polling mechanism
let resultResponse
let retries = 0
let resultJson
while (retries < 5) {
await new Promise((resolve) => setTimeout(resolve, 2000)) // wait for 2 seconds
resultResponse = await fetch(
`https://cors-anywhere.herokuapp.com/https://www.virustotal.com/api/v3/analyses/${analysisIdValue}`,
{
method: 'GET',
headers: {
'x-apikey':
'apikey',
},
}
)
resultJson = await resultResponse.json()
if (resultJson.data.attributes.status === 'completed') {
break
}
retries++
}
if (resultResponse.ok) {
const malicious = resultJson.data.attributes.stats.malicious > 0
const resultText = malicious
? 'Phishing detected!'
: 'Safe from phishing :)'
return resultText // Return the result text
} else {
return 'Error: Analysis failed' // Return an error message
}
} catch (error) {
console.error('Error analyzing page:', error)
return 'Error: Analysis failed' // Return an error message
}
}
chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) => {
if (request.action === 'analyzePageGuest') {
let tabId
if (sender.tab) {
tabId = sender.tab.id
} else {
const tabs = await chrome.tabs.query({
active: true,
currentWindow: true,
})
if (tabs.length > 0) {
tabId = tabs[0].id
} else {
console.info('No tabs found!')
sendResponse({ result: 'No tabs found!' }) // Return an error message
return false
}
}
if (tabId) {
console.info('Tab ID:', tabId)
const tab = await chrome.tabs.get(tabId)
console.info('Tab URL:', tab.url)
try {
const resultText = await analyzePageGuest(tabId, {}, tab)
console.info('Result text:', resultText)
sendResponse({ result: resultText })
} catch (error) {
console.error('Error analyzing page:', error)
sendResponse({ result: 'Error analyzing page' })
}
}
return true
}
})
всплывающее окно.js
const button = document.querySelector('.button')
const resultElement = document.getElementById('result')
button.addEventListener('click', () => {
chrome.runtime.sendMessage({ action: 'analyzePageGuest' }, (response) => {
if (response && response.result) {
console.info('Received response:', response)
resultElement.innerText = response.result
}
})
setTimeout(() => {
if (!resultElement.innerText) {
resultElement.innerText =
'Analysis not completed. Please try again later.'
}
}, 4000)
})
всплывающее окно.html
<div class = "popup-container">
<span id = "current-url"></span>
<button class = "button">
<span class = "submit">Analyze page</span>
<span class = "loading"><i class = "fas fa-circle-notch fa-spin"></i></i></span>
<span class = "check"><i class = "fa fa-check"></i></span>
</button>
<span id = "result"></span>
</div>
Я уже добавил return true в асинхронную функцию, но она не работает..
Так. Чтобы ваш код заработал, вам необходимо внести несколько очень важных изменений.
Ваша функция прослушивателя не должна быть асинхронной. Согласно документации:
Предупреждение: не добавляйте async к функции. Добавление async меняет смысл отправки асинхронного ответа с использованием обещания, что фактически аналогично sendResponse(true).
Это должно выглядеть так:
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {})
И самое важное! Вы все делаете правильно. Вы возвращаете true для обработки асинхронного ответа, но неправильно вызываете функцию sendResponse
. Функция sendResponse
должна вызываться после получения результата в Promise.then(response => sendResponse(response))
.
Я не рассматривал логику вашей функции analyzePageGuest
, но окончательная функция прослушивателя должна выглядеть примерно так:
async function getActiveTab() {
const tabs = await chrome.tabs.query({ active: true });
let activeTab = null;
tabs?.forEach((tab) => {
if (!activeTab || tab.lastAccessed > activeTab.lastAccessed) {
activeTab = tab;
}
});
return activeTab;
}
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
switch (request.action) {
case 'analyzePageGuest':
getActiveTab().then(activeTab => {
analyzePageGuest(activeTab.id, {}, activeTab)
.then(response => sendResponse(response))
.catch(() => sendResponse({ result: 'Error analyzing page' }));
});
return true;
}
});
Чтобы получить URL-адрес активной вкладки, у вас должно быть разрешение tabs
на manifest.json
:
// manifest.json
...
"permissions": [
"tabs"
]
...
Спасибо за Ваш ответ! В итоге я сохранил результат в локальном хранилище, поэтому во всплывающем окне я просто извлекаю его с помощью Storage.get, но все равно спасибо за ответ!