notification.requestpermission()必须在用户真实手势(如click、keydown)的同步回调中立即调用,禁止在onload、settimeout等非交互上下文中执行;需先检查notification.permission状态,仅当为"default"时才可调用,且不可异步延迟。

Notification 权限不能自动申请,必须由用户真实点击、按键等交互触发,否则浏览器直接静默拒绝,控制台报 NotAllowedError 或返回 "denied"。
为什么 Notification.requestPermission() 总是失败?
常见错误是把它放在 window.onload、DOMContentLoaded 甚至 setTimeout 里——这些都不是用户手势(user gesture)。Chrome、Firefox、Edge 全部强制拦截,连弹窗都不会出现,permission 状态直接变成 "denied" 或卡在 "default" 不变。
- 只允许在
click、keydown(且event.isTrusted === true)、submit等真实交互回调中调用 - 哪怕加了
event.preventDefault(),只要事件是用户主动触发的,仍算有效手势 - 用
button比用div+onclick更稳妥,部分浏览器对非原生可交互元素的手势识别更严格
怎么安全地判断和申请权限?
不能跳过状态检查直接调用 requestPermission()。必须先读 Notification.permission,再按状态分支处理:
-
"granted":直接new Notification() -
"denied":不调用requestPermission(),弹提示引导用户去浏览器设置手动开启(chrome://settings/content/notifications) -
"default":此时才可调用requestPermission(),且必须在用户点击后立即执行(不能异步延迟)
示例逻辑:
document.getElementById('enable-notif').addEventListener('click', () => {
if (Notification.permission === 'granted') {
showNotification();
} else if (Notification.permission === 'default') {
Notification.requestPermission().then(perm => {
if (perm === 'granted') showNotification();
});
}
});
new Notification() 报 TypeError: Illegal constructor 怎么办?
这个错几乎只发生在 HTTP 环境(非 HTTPS、非 localhost)。即使页面能加载,构造函数也会直接抛错——不是权限问题,是协议限制。
- 开发阶段用
http://localhost:xxxx没问题,但http://127.0.0.1或http://local.test都不行 - 生产环境必须部署在 HTTPS 下,自签名证书也不行(浏览器不认)
- 某些旧版 Edge 还要求
icon路径必须是同源绝对路径,相对路径或跨域 URL 可能导致静默失败
iOS Safari 和部分安卓 WebView 完全不支持怎么办?
这不是权限没开的问题,是平台级缺失。iOS Safari 自始至终没实现 Notification API,所有调用都会跳过或报错;很多安卓 WebView(尤其国内定制版)也直接返回 false 或不触发回调。
- 务必用
"Notification" in window做运行时检测,不要只靠 UA 判断 - 降级方案建议:在不支持时 fallback 到页面内 toast 提示 + 小红点 + 消息中心未读数,别依赖桌面通知做关键路径
- 不要在
requestPermission()的catch里埋日志就完事,得有明确 UI 引导(比如“您的浏览器暂不支持桌面提醒”)
最常被忽略的一点:权限状态一旦是 "denied",后续任何调用 requestPermission() 都不会弹窗,也不会改变状态。这时候唯一办法是让用户自己进浏览器设置翻白眼——代码什么都做不了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











