Obtuve productos de carrito en mi sitio web de comercio electrónico que construí con Angular, NodeJS, MongoDB. Cuando mi cliente quiere agregar cantidad o disminuir cantidad de producto por ejemplo de 4 a 2, enviará 2 solicitudes de parche para actualizar la cantidad (la primera de 4 a 3 y la segunda de 3 a 2), quiero que haga una Algoritmo mucho mejor que funcionará en 1 solicitud (por ejemplo, al final de la sesión, cuando el usuario abandona el sitio web, etc.) Intenté usar Navigator.sendBeacon y a veces funciona y otras veces no (que no puedo uso, necesito algo que funcione todo el tiempo ...) No quiero mostrarle al usuario ningún mensaje antes de que se vaya, lo que sé que soluciona ese problema y funcionará con navigator.sendBeacon Esto es lo que hice con navigator.sendBeacon:
Lado del cliente:
@HostListener('window:beforeunload', ['$event']) onBeforeUnload(): void { const data = new FormData(); data.append('cartProducts', JSON.stringify(this.cartProducts)); navigator.sendBeacon("http://localhost:3000/api/shopping-online/get-beacon", data) } public cartProducts: CartItem[] = [];Cart products obtiene la matriz de objetos de la base de datos.
Lado del servidor:
router.post("/get-beacon", async (request, response) => { try { console.log("hi"); } catch (err) { console.log("bye"); } })A veces recibo el mensaje "hola" en el terminal NodeJS y, a veces, llega con un retraso de unos segundos y, a veces, no aparece en absoluto.
Estaré encantado de cualquier idea con navigator.sendBeacon o cualquier otra idea que tenga para detener ese mal algoritmo que cada clic en la cantidad de cambio envía al lado del servidor (pueden ser incluso 10 clics seguidos, lo cual es muy malo).
¿Ha intentado escuchar el cambio de visibilitychange en lugar de usar onBeforeUnload ?
document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'hidden') { const data = new FormData(); data.append('cartProducts', JSON.stringify(this.cartProducts)); navigator.sendBeacon("http://localhost:3000/api/shopping-online/get-beacon", data); } });Con un gran consejo de Alan obtuve exactamente lo que quería, aquí está la solución. Por cierto, no se menciona cómo obtener exactamente el sendBeacon en NodeJS, así que lo agregaré hasta aquí.
Lado del cliente (angular):
@HostListener('document:visibilitychange', ['$event']) visibilitychange() { if (this.cartProducts && this.isCartProductsChanged) { const blob = new Blob([JSON.stringify(this.cartProducts)], { type: 'application/json' }); navigator.sendBeacon("http://localhost:3000/api/shopping-online/get-beacon", blob) this.isCartProductsChanged = false; } } public cartProducts: CartItem[] = []; public isCartProductsChanged: boolean = false;Enviará la baliza solo si hay productos en el carrito, solo si se realizaron cambios en el carrito (cantidad o producto agregado)
Lado del servidor (NodeJS):
En el controlador:
router.post("/get-beacon", async (request, response) => { try { console.log(request.body); } catch (err) { console.log("bye"); } })En aplicación.js
const shoppingController = require("./controllers/shopping-controller"); const express = require("express"); const server = express(); const cors = require("cors"); server.use(function (req, res, next) { res.header("Access-Control-Allow-Credentials", "true"); res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content- Type, Accept"); next(); }); server.use(express.text()); let port = process.env.PORT || 3000; server.use("/api/shopping-online", shoppingController); server.listen(port, () => console.log(`Listening on http://localhost:${port}`));El uso en lugar del analizador corporal desde la versión express 4.16.0 para que funcione es
server.use(express.text());Antes de la versión express 4.16.0, debe instalar body-parser
npm i body-parserY agregue en app.js:
const bodyParser = require("body-parser"); server.use(bodyParser.text());