Я пытаюсь сохранить пользовательские данные, когда запускается событие JavaScript «перед выгрузкой». Я вызываю серверную функцию (облачные функции firebase), которая просто получает объект от пользователя и обновляет документ. Функция срабатывает, но из консоли firebase я вижу, что она завершена с кодом 204. Вот мой клиентский код
window.onbeforeunload = function() {
firefun_ref(data);
}
Сторона сервера:
exports.updateStats = functions.https.onCall(async (data, context) => {
return admin.firestore().collection("stats")
.doc((new Date()).toISOString().substring(0, 10))
.update(filter(data));
});
Я хочу отметить, что если я запускаю функцию саму по себе, она работает нормально, просто вызывает проблемы, когда она находится в событии перед выгрузкой.
Это будет невозможно.
Браузеры строго ограничивают то, что вам разрешено делать на мероприятии beforeunload
, потому что это может привести к злоупотреблениям. Асинхронные события не допускаются (поскольку они могут заставить окно оставаться открытым в течение произвольного периода времени после того, как пользователь захочет его закрыть).
Насколько мне известно, единственным надежным использованием onbeforeunload
является отображение подсказки, позволяющей пользователю передумать; некоторые браузеры позволят вам настроить отображаемый текст (путем возврата строки из обработчика beforeunload
), некоторые браузеры всегда будут отображать текст по умолчанию:
window.addEventListener('beforeunload', function (e) {
// Cancel the event
e.preventDefault(); // If you prevent default behavior in Mozilla Firefox prompt will always be shown
// Chrome requires returnValue to be set
e.returnValue = '';
});
https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload
Вместо этого вы можете взглянуть на отправитьМаяк, боюсь, я недостаточно знаком с ним, чтобы давать советы по использованию, но он может удовлетворить ваши потребности.
Если данные, которые вы хотите записать, известны до того, как пользователь закроет вкладку, вы можете зарегистрировать так называемый onDisconnect
обработчик в базе данных реального времени (другая база данных, которая является частью Firebase).
Обработчик onDisconnect
— это операция отложенной записи, которая запускается, как только сервер замечает, что клиент отключился, либо потому, что SDK в этом клиенте сообщает об этом перед отключением, либо потому, что время ожидания сокета на сервере истекло (что может занять несколько минут). ).
В Firestore не существует эквивалента, потому что его проводной протокол не требует установления соединения, а база данных реального времени работает на основе (веб-сокетов). Если вы хотите интегрировать это в Firestore, ознакомьтесь с документацией по создание системы присутствия в Firestore с использованием базы данных реального времени.
Я пытаюсь заставить это работать с API маяка и даже нашел хук:
/*
see https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon
```jsx
const MyComponent = ({ children }) => {
// will get fired if the page unloads while the component is mounted
useUnloadBeacon({
url: 'https://api.my.site/route',
payload: () => {
return 'something'
}
})
return children
}
```
*/
import { useEffect } from "react"
export const useUnloadBeacon = ({
url = "",
payload = () => {},
}) => {
const eventHandler = () => navigator.sendBeacon(url, payload())
useEffect(() => {
window.addEventListener("unload", eventHandler, true)
return () => {
window.removeEventListener("unload", eventHandler, true)
}
}, [])
}
Единственная проблема, с которой я сталкиваюсь, - это запуск облачной функции. Я отправляю запрос на получение, но он почему-то не срабатывает.
app.post("/setStatusToOpen", setStatusToOpen)
const setStatusToOpen = async (req, res) => {
console.info("setStatusToOpen, req.query", req.query)
const { documentId } = req.query
try {
const setPayload = { status: "open" }
firestore
.doc(`messageInABottle/${documentId}`)
.set(setPayload, { merge: true })
return res.send(true)
} catch (error) {
console.info("Error in getMessageInABottleRecipient:", error)
return res.send(error)
}
}
Я думаю, что это как-то связано с неправильными заголовками.
Так нет ли способа сохранить данные в фоновом режиме, когда пользователь уходит?