卸载前调用服务器端函数(firebase)
Call server side function before unload (firebase)
我正在尝试在触发 JavaScript 事件“beforeunload”时保存用户数据。我调用了一个服务器端函数(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
活动中可以做的事情,因为它很容易被滥用。不允许异步事件(因为它们可能会强制 window 在用户想要关闭它后保持打开任意时间。)
据我所知,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
如果您要写入的数据在用户关闭选项卡之前已知,您可以在实时数据库(属于 Firebase 的另一个数据库)中注册 so-called onDisconnect
handler。
onDisconnect
处理程序是一个延迟的写入操作,一旦服务器注意到客户端已断开连接,它就会立即运行,这可能是因为客户端中的 SDK 在断开连接之前通知它,也可能是因为套接字超时服务器(可能需要几分钟)。
Firestore 上不存在等效协议,因为它的有线协议是无连接的,而实时数据库基于(网络)套接字工作。如果您想将其集成到 Firestore 中,请查看 building a presence system in Firestore by using the Realtime Database.
上的文档
我试图让它与 Beacon 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.log("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.log("Error in getMessageInABottleRecipient:", error)
return res.send(error)
}
}
我认为这与headers不正确有关。
我正在尝试在触发 JavaScript 事件“beforeunload”时保存用户数据。我调用了一个服务器端函数(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
活动中可以做的事情,因为它很容易被滥用。不允许异步事件(因为它们可能会强制 window 在用户想要关闭它后保持打开任意时间。)
据我所知,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
如果您要写入的数据在用户关闭选项卡之前已知,您可以在实时数据库(属于 Firebase 的另一个数据库)中注册 so-called onDisconnect
handler。
onDisconnect
处理程序是一个延迟的写入操作,一旦服务器注意到客户端已断开连接,它就会立即运行,这可能是因为客户端中的 SDK 在断开连接之前通知它,也可能是因为套接字超时服务器(可能需要几分钟)。
Firestore 上不存在等效协议,因为它的有线协议是无连接的,而实时数据库基于(网络)套接字工作。如果您想将其集成到 Firestore 中,请查看 building a presence system in Firestore by using the Realtime Database.
上的文档我试图让它与 Beacon 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.log("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.log("Error in getMessageInABottleRecipient:", error)
return res.send(error)
}
}
我认为这与headers不正确有关。