使用 Web 推送时,一个痛点是触发推送消息 要触发推送消息,应用需要向推送发出 POST 请求 用于通过网络推送之后的公共服务 协议。要在所有广告系列中使用推送功能 您需要使用 VAPID (又称为应用服务器密钥),这通常要求设置一个标头,并用一个值证明 您的应用可以向用户发送消息。要使用推送消息发送数据,数据需要 已加密和特定标头 ,这样浏览器才能正确解密邮件。
触发推送的主要问题在于,如果遇到问题,就很难诊断 问题。随着时间的推移以及浏览器的支持越来越广泛,这一问题会不断改善,但要做到这一点却并非易事。对于 因此,我强烈建议使用库来处理加密、格式设置和 触发您的推送消息。
如果你确实想了解这些库在做什么 。现在,我们将了解如何管理订阅以及如何使用 现有的网络推送库来发出推送请求。
在本节中,我们将使用 web-push Node 库。其他语言会有所不同 不会有太大的差异我们现在看到的是 Node,因为它是 JavaScript,应该就是 最符合读者的阅读习惯
我们将完成以下步骤:
- 向后端发送订阅并保存。
- 检索已保存的订阅并触发推送消息。
保存订阅
从数据库保存和查询 PushSubscription
的方法取决于
您的服务器端语言和数据库选择,
示例。
在演示版网页中,系统会通过发出一个简单的 POST 请求将 PushSubscription
发送到我们的后端:
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.');
}
});
}
我们的演示中的 Express 服务器为
/api/save-subscription/
端点:
app.post('/api/save-subscription/', function (req, res) {
在此路由中,我们会验证订阅,以确保请求正常且没有 垃圾:
const isValidSaveRequest = (req, res) => {
// Check the request body has at least an endpoint.
if (!req.body || !req.body.endpoint) {
// Not a valid subscription.
res.status(400);
res.setHeader('Content-Type', 'application/json');
res.send(
JSON.stringify({
error: {
id: 'no-endpoint',
message: 'Subscription must have an endpoint.',
},
}),
);
return false;
}
return true;
};
如果订阅有效,我们需要保存它并返回相应的 JSON 响应:
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.',
},
}),
);
});
此演示使用 nedb 来存储订阅, 简单的基于文件的数据库,但您可以选择使用任何数据库。我们仅将其用作 无需进行任何设置对于生产环境,您希望使用更可靠的系统。(我倾向于 继续使用良好的旧版 MySQL。)
function saveSubscriptionToDatabase(subscription) {
return new Promise(function (resolve, reject) {
db.insert(subscription, function (err, newDoc) {
if (err) {
reject(err);
return;
}
resolve(newDoc._id);
});
});
}
发送推送消息
在发送推送消息时,我们最终需要某个事件来触发
向用户发送消息一种常用的方法是创建管理页面
配置和触发推送消息。但您可以创建一个在本地运行的程序
另一种方法,允许访问 PushSubscription
的列表并运行代码
触发推送消息。
我们的演示中有“管理员喜欢”功能可触发推送的页面上由于它只是一个演示 公共页面。
我将逐一介绍使演示版正常运行所需的每个步骤。这些就是 以便所有人(包括刚接触 Node 的用户)都能有的放矢。
我们在讨论订阅用户的过程中,介绍了如何将 applicationServerKey
添加到
subscribe()
个选项。在后端,我们需要此私钥。
在本演示中,这些值会像这样添加到我们的 Node 应用中(我知道一些枯燥的代码,但只是想 (您知道这并非魔法):
const vapidKeys = {
publicKey:
'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
privateKey: 'UUxI4O8-FbRouAevSmBQ6o18hgE4nSG3qwvJTfKc-ls',
};
接下来,我们需要为 Node 服务器安装 web-push
模块:
npm install web-push --save
然后,在我们的 Node 脚本中,我们需要 web-push
模块
如下所示:
const webpush = require('web-push');
现在,我们可以开始使用 web-push
模块了。首先,我们需要告知 web-push
模块
应用服务器密钥(请注意,它们也称为 VAPID 密钥,
。)
const vapidKeys = {
publicKey:
'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
privateKey: 'UUxI4O8-FbRouAevSmBQ6o18hgE4nSG3qwvJTfKc-ls',
};
webpush.setVapidDetails(
'mailto:web-push-book@gauntface.com',
vapidKeys.publicKey,
vapidKeys.privateKey,
);
请注意,我们还添加了“mailto:”字符串。此字符串必须是网址或 mailto 电子邮件地址。这一条信息实际上将作为 请求以触发推送。这样做的原因是,如果 Web 推送服务需要 与发件人取得联系时,对方提供了一些信息。
至此,web-push
模块可供使用,下一步是触发推送消息。
该演示使用模拟管理控制台触发推送消息。
![“管理”页面的屏幕截图。](https://web.developers.google.cn/static/articles/sending-messages-with-web-push-libraries/image/screenshot-the-admin-pag-7bb2e26069ffc.png?authuser=0000&hl=nb)
点击“Trigger Push Message”(触发推送消息)按钮会向 /api/trigger-push-msg/
发出 POST 请求,
这是后端发送推送消息的信号
express:
app.post('/api/trigger-push-msg/', function (req, res) {
收到此请求后,我们会从数据库获取订阅, 就会触发推送消息
return getSubscriptionsFromDatabase().then(function (subscriptions) {
let promiseChain = Promise.resolve();
for (let i = 0; i < subscriptions.length; i++) {
const subscription = subscriptions[i];
promiseChain = promiseChain.then(() => {
return triggerPushMsg(subscription, dataToSend);
});
}
return promiseChain;
});
然后,函数 triggerPushMsg()
可以使用 web-push 库将消息发送到
提供的订阅。
const triggerPushMsg = function (subscription, dataToSend) {
return webpush.sendNotification(subscription, dataToSend).catch((err) => {
if (err.statusCode === 404 || err.statusCode === 410) {
console.log('Subscription has expired or is no longer valid: ', err);
return deleteSubscriptionFromDatabase(subscription._id);
} else {
throw err;
}
});
};
调用 webpush.sendNotification()
将返回一个 promise。如果
则 promise 将会解析,并且
我们无需执行任何操作。如果 promise 拒绝,你需要检查
错误,因为它会告知您 PushSubscription
是否仍在
是否有效。
要确定推送服务发生的错误类型,最好查看状态代码。错误 推送服务的消息会有所不同,有些消息比其他服务更有用。
在此示例中,它会检查状态代码 404
和 410
,它们是
“未找到”“Gone”如果我们收到上述任一消息,则表示订阅已过期
或不再有效。在这些情况下,我们需要从数据库中移除订阅。
如果出现其他错误,我们只使用 throw err
,这会使
triggerPushMsg()
则拒绝。
我们将在下一部分介绍 Web 推送时,介绍其他一些状态代码 协议。
循环遍历订阅后,我们需要返回 JSON 响应。
.then(() => {
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-send-messages',
message: `We were unable to send messages to all subscriptions : ` +
`'${err.message}'`
}
}));
});
我们介绍了主要的实现步骤:
- 创建 API 以将订阅从网页发送到后端 以便将其保存到数据库
- 创建 API 以触发推送消息的发送(在本例中为 从假装管理面板中调用的 API)。
- 从后端检索所有订阅 并使用一个 web-push 库。
无论使用哪种后端(Node、PHP、Python 等),实现推送的步骤都一样, 都保持不变
接下来,这些网络推送库究竟能为我们做些什么?