Suscribir a un usuario

El primer paso es obtener el permiso del usuario para enviarle mensajes de inserción y, luego, podemos obtén un PushSubscription.

La API de JavaScript para hacer esto es razonablemente sencilla, así que a través del flujo lógico.

Detección de funciones

Primero, debemos comprobar si el navegador actual es compatible con los mensajes push. Podemos comprobar si push es compatible con dos verificaciones simples.

  1. Busca serviceWorker en navigator.
  2. Busca PushManager en la ventana.
if (!('serviceWorker' in navigator)) {
  // Service Worker isn't supported on this browser, disable or hide UI.
  return;
}

if (!('PushManager' in window)) {
  // Push isn't supported on this browser, disable or hide UI.
  return;
}

Si bien la compatibilidad con los navegadores está aumentando rápidamente tanto para service worker como mensajes push, siempre es buena idea detectar tanto mejorar progresivamente.

Registra un service worker

Con la detección de funciones, sabemos que se admiten tanto service workers como Push. El próximo paso es "registrarse" nuestro service worker.

Cuando registramos un service worker, le indicamos al navegador dónde se encuentra nuestro archivo. El archivo sigue siendo solo JavaScript, pero el navegador le "otorgará acceso" al service worker APIs, incluidas las de envío. Para ser más exactos, el navegador ejecuta el archivo en un service worker en un entorno de nube.

Para registrar un service worker, llama a navigator.serviceWorker.register() y pasa la ruta de acceso a nuestro archivo. De esta forma:

function registerServiceWorker() {
  return navigator.serviceWorker
    .register('/service-worker.js')
    .then(function (registration) {
      console.log('Service worker successfully registered.');
      return registration;
    })
    .catch(function (err) {
      console.error('Unable to register service worker.', err);
    });
}

Esta función le indica al navegador que tenemos un archivo de service worker y dónde se encuentra. En En este caso, el archivo del service worker se encuentra en /service-worker.js. En segundo plano, el navegador realizará los siguientes pasos después de llamar a register():

  1. Descarga el archivo del service worker.

  2. Ejecuta JavaScript.

  3. Si todo se ejecuta correctamente y no hay errores, se mostrará la promesa que muestra register(). resolverá. Si hay errores de cualquier tipo, se rechazará la promesa.

Si se rechaza register(), vuelve a revisar tu JavaScript para ver si hay errores tipográficos o de error en las Herramientas para desarrolladores de Chrome.

Cuando se resuelve register(), muestra una ServiceWorkerRegistration. Usaremos esta para acceder a la API de PushManager.

Compatibilidad con el navegador de la API de PushManager

Navegadores compatibles

  • Chrome: 42.
  • Límite: 17.
  • Firefox: 44.
  • Safari: 16.

Origen

Solicitando permiso

Registramos nuestro service worker y estamos listos para suscribir al usuario. El siguiente paso es permiso del usuario para enviarle mensajes de inserción.

La API para obtener permisos es relativamente simple, pero la desventaja es que La API recientemente cambió de realizar una devolución de llamada a mostrar una promesa. El problema con esto, es que no podemos saber qué versión de la API implementa la versión por lo que debes implementar y manejar ambos.

function askPermission() {
  return new Promise(function (resolve, reject) {
    const permissionResult = Notification.requestPermission(function (result) {
      resolve(result);
    });

    if (permissionResult) {
      permissionResult.then(resolve, reject);
    }
  }).then(function (permissionResult) {
    if (permissionResult !== 'granted') {
      throw new Error("We weren't granted permission.");
    }
  });
}

En el código anterior, el fragmento de código importante es la llamada a Notification.requestPermission() Este método mostrará un mensaje al usuario:

Mensaje de permiso en Chrome para computadoras y dispositivos móviles.

Una vez que el usuario interactuó con la solicitud de permiso presionando Permitir, Bloquear o simplemente cerrándola, obtendremos el resultado como una cadena: 'granted', 'default' o 'denied'.

En el código de muestra anterior, la promesa que devuelve askPermission() se resuelve si el permiso de lo contrario, se arrojará un error y se rechazará la promesa.

Un caso límite que debes controlar es que si el usuario hace clic en . Si esta tu aplicación web no podrá volver a solicitar permiso al usuario. Tendrá que “desbloquear” manualmente tu app cambiando el estado de permisos, que está oculto en un panel de configuración. Piensa bien cómo y cuándo le pides permiso al usuario porque, si hacen clic en un bloque, no es una forma fácil de revertir esa decisión.

La buena noticia es que a la mayoría de los usuarios les gusta dar permiso, siempre y cuando saben por qué se solicita el permiso.

Analizaremos cómo algunos sitios populares solicitan permiso más adelante.

Suscribir usuarios con PushManager

Una vez que tenemos el service worker registrado y tenemos el permiso, podemos suscribir un usuario llamando a registration.pushManager.subscribe().

function subscribeUserToPush() {
  return navigator.serviceWorker
    .register('/service-worker.js')
    .then(function (registration) {
      const subscribeOptions = {
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(
          'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
        ),
      };

      return registration.pushManager.subscribe(subscribeOptions);
    })
    .then(function (pushSubscription) {
      console.log(
        'Received PushSubscription: ',
        JSON.stringify(pushSubscription),
      );
      return pushSubscription;
    });
}

Cuando llamamos al método subscribe(), pasamos un objeto options, que consiste en parámetros obligatorios y opcionales.

Veamos todas las opciones que podemos pasar.

Opciones userVisibleOnly

Cuando se agregó push a los navegadores, no había certeza acerca de si los desarrolladores debían enviar un mensaje push y no mostrar una notificación. Esto se conoce comúnmente como silencioso push, debido a que el usuario no sabía que algo había sucedido en segundo plano.

La preocupación era que los desarrolladores podían hacer cosas desagradables, como hacer un seguimiento de la ubicación de un usuario en una de forma continua sin que el usuario lo sepa.

A fin de evitar esta situación y darles tiempo a los autores de las especificaciones para que consideren la mejor manera de respaldarla , se agregó la opción userVisibleOnly, y pasar un valor de true es un valor un acuerdo con el navegador de que la aplicación web mostrará una notificación cada vez que se ejecute un recibidos (es decir, no hay envío silencioso).

Por el momento, debes pasar un valor de true. Si no incluyes Si pasas la clave userVisibleOnly o pasas false, verás el siguiente error:

Actualmente, Chrome solo admite la API de Push para las suscripciones que generarán visibles para el usuario. Puedes indicarlo llamando a pushManager.subscribe({userVisibleOnly: true}) en su lugar. Consulta https://goo.gl/yqv4Q4 para obtener más información.

En este momento, parece que la función de envío silencioso general no se implementará en Chrome. En cambio, los autores de las especificaciones están explorando la noción de una API de presupuesto que permitirá a las aplicaciones web un cierto la cantidad de mensajes push silenciosos basados en el uso de una app web.

Opción applicationServerKey

Mencionamos brevemente las “claves del servidor de aplicaciones” en la sección anterior. "Aplicación las claves del servidor” las usa un servicio push para identificar la aplicación que suscribe a un usuario y y asegurarse de que la misma aplicación envíe mensajes a ese usuario.

Las claves del servidor de aplicaciones son un par de claves públicas y privadas que son exclusivas de tu aplicación. Debes mantener la clave privada en secreto para tu aplicación, y puedes compartir la clave pública. libremente.

La opción applicationServerKey que se pasa a la llamada subscribe() es el nombre público . El navegador pasa esto a un servicio push cuando se suscribe al usuario, es decir, puede vincular la clave pública de tu aplicación con el PushSubscription del usuario.

En el siguiente diagrama, se ilustran estos pasos.

  1. Tu app web se carga en un navegador, llamas a subscribe() y pasas tu de la clave del servidor de la app.
  2. El navegador luego hace una solicitud de red a un servicio de envío, que generará un extremo, asociar este extremo con la clave pública de la aplicación y devolverlo al navegador.
  3. El navegador agregará este extremo a PushSubscription, que se muestra a través del subscribe().

Ilustración de la clave del servidor de la aplicación pública que se usa en la suscripción
.

Cuando quieras enviar un mensaje push, tendrás que crear un encabezado de Authorization que contendrá información firmada con la clave privada del servidor de tu aplicación. Cuando El servicio de envío recibe una solicitud para enviar un mensaje de envío, puede validar este encabezado de Authorization firmado. buscando la clave pública vinculada al extremo que recibe la solicitud. Si la firma es válido, el servicio de notificaciones sabe que debe provenir del servidor de aplicaciones con el clave privada coincidente. En pocas palabras, es una medida de seguridad que impide que otra persona envíe a los usuarios de una aplicación.

Cómo se usa la clave privada del servidor de aplicaciones para enviar un
mensaje

Técnicamente, applicationServerKey es opcional. Sin embargo, lo más sencillo implementación en Chrome la requiere y otros navegadores pueden requerirla en el futuro. En Firefox, es opcional.

La especificación que define cuál debe ser la clave del servidor de la aplicación la especificación de VAPID. Cada vez que leas algo que haga referencia a las "claves del servidor de la aplicación" o "Claves VAPID", solo recuerda que son lo mismo.

Cómo crear claves de servidor de aplicaciones

Puedes crear un conjunto público y privado de claves de servidor de aplicaciones en web-push-codelab.glitch.me o puedes usar la línea de comandos web-push para generar claves de la siguiente manera:

    $ npm install -g web-push
    $ web-push generate-vapid-keys

Solo necesitas crear estas claves una vez para tu aplicación, así que asegúrate de mantener privada. (Sí, yo lo dije).

Permisos y subscripción()

Llamar a subscribe() tiene un efecto secundario. Si tu app web no tiene permisos para lo siguiente: mostrar notificaciones cuando se llame a subscribe(), el navegador solicitará la permisos por ti. Esto es útil si tu IU funciona con este flujo, pero si quieres (y creo que la mayoría de los desarrolladores lo harán), sigue la API de Notification.requestPermission(). que usamos anteriormente.

¿Qué es una PushSubscription?

Llamamos a subscribe(), pasamos algunas opciones y, a cambio, obtenemos una promesa que da como resultado un PushSubscription, lo que da como resultado un código como el siguiente:

function subscribeUserToPush() {
  return navigator.serviceWorker
    .register('/service-worker.js')
    .then(function (registration) {
      const subscribeOptions = {
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(
          'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
        ),
      };

      return registration.pushManager.subscribe(subscribeOptions);
    })
    .then(function (pushSubscription) {
      console.log(
        'Received PushSubscription: ',
        JSON.stringify(pushSubscription),
      );
      return pushSubscription;
    });
}

El objeto PushSubscription contiene toda la información necesaria para enviar un mensaje. mensajes a ese usuario. Si imprimes el contenido con JSON.stringify(), verás lo siguiente: lo siguiente:

    {
      "endpoint": "https://some.pushservice.com/something-unique",
      "keys": {
        "p256dh":
    "BIPUL12DLfytvTajnryr2PRdAgXS3HGKiLqndGcJGabyhHheJYlNGCeXl1dn18gSJ1WAkAPIxr4gK0_dQds4yiI=",
        "auth":"FPssNDTKnInHVndSTdbKFw=="
      }
    }

endpoint es la URL de los servicios de envío. Para activar un mensaje de envío, realiza una solicitud POST a esta URL.

El objeto keys contiene los valores que se usan para encriptar los datos de los mensajes que se enviaron con un mensaje push (de lo que hablaremos más adelante en esta sección).

Volver a suscribirse periódicamente para evitar el vencimiento

Cuando te suscribes a las notificaciones push, por lo general recibes un PushSubscription.expirationTime de null. En teoría, esto significa que la suscripción nunca vence (a diferencia de cuando recibes un DOMHighResTimeStamp, que te indica el momento exacto en el que vence la suscripción). Sin embargo, en la práctica, es común que los navegadores sigan permitiendo que las suscripciones caduquen, por ejemplo, si no se reciben notificaciones push durante más tiempo o si el navegador detecta que el usuario no está usando una app que no tiene el permiso de notificaciones push. Un patrón para evitar esto es volver a suscribir al usuario en cada notificación recibida, como se muestra en el siguiente fragmento. Para ello, debes enviar notificaciones con la frecuencia necesaria para que el navegador no venza automáticamente la suscripción, y debes sopesar con mucho cuidado las ventajas y desventajas de las necesidades de notificaciones legítimas contra el envío involuntario de spam al usuario para que la suscripción no venza. En última instancia, no debes intentar luchar contra el navegador para proteger al usuario de suscripciones a notificaciones olvidadas durante mucho tiempo.

/* In the Service Worker. */

self.addEventListener('push', function(event) {
  console.log('Received a push message', event);

  // Display notification or handle data
  // Example: show a notification
  const title = 'New Notification';
  const body = 'You have new updates!';
  const icon = '/images/icon.png';
  const tag = 'simple-push-demo-notification-tag';

  event.waitUntil(
    self.registration.showNotification(title, {
      body: body,
      icon: icon,
      tag: tag
    })
  );

  // Attempt to resubscribe after receiving a notification
  event.waitUntil(resubscribeToPush());
});

function resubscribeToPush() {
  return self.registration.pushManager.getSubscription()
    .then(function(subscription) {
      if (subscription) {
        return subscription.unsubscribe();
      }
    })
    .then(function() {
      return self.registration.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array('YOUR_PUBLIC_VAPID_KEY_HERE')
      });
    })
    .then(function(subscription) {
      console.log('Resubscribed to push notifications:', subscription);
      // Optionally, send new subscription details to your server
    })
    .catch(function(error) {
      console.error('Failed to resubscribe:', error);
    });
}

Envía una suscripción a tu servidor

Cuando tengas una suscripción de envío, querrás enviarla a tu servidor. Tú decides cómo una pequeña sugerencia: usar JSON.stringify() para obtener todos los datos necesarios de la objeto de suscripción. De forma alternativa, puedes armar la misma manualmente de la siguiente manera:

const subscriptionObject = {
  endpoint: pushSubscription.endpoint,
  keys: {
    p256dh: pushSubscription.getKeys('p256dh'),
    auth: pushSubscription.getKeys('auth'),
  },
};

// The above is the same output as:

const subscriptionObjectToo = JSON.stringify(pushSubscription);

El envío de la suscripción se realiza desde la página web de la siguiente manera:

function sendSubscriptionToBackEnd(subscription) {
  return fetch('/api/save-subscription/', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(subscription),
  })
    .then(function (response) {
      if (!response.ok) {
        throw new Error('Bad status code from server.');
      }

      return response.json();
    })
    .then(function (responseData) {
      if (!(responseData.data && responseData.data.success)) {
        throw new Error('Bad response from server.');
      }
    });
}

El servidor de nodos recibe esta solicitud y guarda los datos en una base de datos para usarlos más adelante.

app.post('/api/save-subscription/', function (req, res) {
  if (!isValidSaveRequest(req, res)) {
    return;
  }

  return saveSubscriptionToDatabase(req.body)
    .then(function (subscriptionId) {
      res.setHeader('Content-Type', 'application/json');
      res.send(JSON.stringify({data: {success: true}}));
    })
    .catch(function (err) {
      res.status(500);
      res.setHeader('Content-Type', 'application/json');
      res.send(
        JSON.stringify({
          error: {
            id: 'unable-to-save-subscription',
            message:
              'The subscription was received but we were unable to save it to our database.',
          },
        }),
      );
    });
});

Con los detalles de PushSubscription en nuestro servidor, podemos enviar al usuario un mensaje cuando queramos.

Volver a suscribirse periódicamente para evitar el vencimiento

Cuando te suscribes a las notificaciones push, por lo general recibes un PushSubscription.expirationTime de null. En teoría, esto significa que la suscripción nunca vence (a diferencia de cuando recibes un DOMHighResTimeStamp, que te indica el momento exacto en el que vence la suscripción). Sin embargo, en la práctica, es común que los navegadores sigan permitiendo que las suscripciones caduquen, por ejemplo, si no se recibieron notificaciones push durante mucho tiempo o si el navegador detecta que el usuario no está usando la app que tiene el permiso de notificaciones push. Un patrón para evitar esto es volver a suscribir al usuario en cada notificación recibida, como se muestra en el siguiente fragmento. Para ello, debes enviar notificaciones con la frecuencia suficiente para que el navegador no venza automáticamente la suscripción, y debes sopesar con mucho cuidado las ventajas y desventajas de las necesidades legítimas de notificaciones con respecto al envío de spam al usuario para que la suscripción no caduque. En última instancia, no debes intentar luchar contra el navegador para proteger al usuario de suscripciones a notificaciones olvidadas durante mucho tiempo.

/* In the Service Worker. */

self.addEventListener('push', function(event) {
  console.log('Received a push message', event);

  // Display notification or handle data
  // Example: show a notification
  const title = 'New Notification';
  const body = 'You have new updates!';
  const icon = '/images/icon.png';
  const tag = 'simple-push-demo-notification-tag';

  event.waitUntil(
    self.registration.showNotification(title, {
      body: body,
      icon: icon,
      tag: tag
    })
  );

  // Attempt to resubscribe after receiving a notification
  event.waitUntil(resubscribeToPush());
});

function resubscribeToPush() {
  return self.registration.pushManager.getSubscription()
    .then(function(subscription) {
      if (subscription) {
        return subscription.unsubscribe();
      }
    })
    .then(function() {
      return self.registration.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array('YOUR_PUBLIC_VAPID_KEY_HERE')
      });
    })
    .then(function(subscription) {
      console.log('Resubscribed to push notifications:', subscription);
      // Optionally, send new subscription details to your server
    })
    .catch(function(error) {
      console.error('Failed to resubscribe:', error);
    });
}

Preguntas frecuentes

Estas son algunas de las preguntas más frecuentes que se han formulado hasta el momento:

¿Puedo cambiar el servicio push que usa un navegador?

No. El navegador selecciona el servicio push y, como vimos con el subscribe(), el navegador realizará solicitudes de red al servicio push para recuperar los detalles que conforman la PushSubscription.

Cada navegador usa un servicio push diferente, ¿no tienen diferentes APIs?

Todos los servicios push esperarán la misma API.

Esta API común se llama Protocolo de envío web y se describe la solicitud de red, que tu aplicación deberá hacer para activar un mensaje de envío.

Si suscribo a un usuario desde su computadora, ¿también se suscribe desde su teléfono?

Lamentablemente, no. Un usuario debe registrarse para el envío en cada navegador que desee para recibir mensajes. También es importante mencionar que esto requerirá el usuario que otorga permiso en cada dispositivo.

Próximos pasos

Code labs