如何解决Laravel项目中navigator.serviceWorker.ready执行停滞问题?
Laravel项目集成通知系统并使用Service Worker,本地运行一切正常,但部署到服务器后功能失效。Service Worker已成功注册并正常运行,但代码执行到console.log('test')语句后便停滞,navigator.serviceWorker.ready相关逻辑无法推进。相关代码如下:
<script> // Request permission for notifications Notification.requestPermission(function(permission) { if (permission === "granted") { console.log("Notification permission granted!"); } else { console.log("Notification permission denied or not defined!"); } }); // Register the service worker navigator.serviceWorker.register("{{ URL::asset('public/service-worker.js') }}").then(function(registration) { console.log('Service worker registered successfully:', registration); }).catch(function(error) { console.error('Error registering service worker:', error); }); // Check if the 'enable' key already exists in local storage if (localStorage.getItem('enable')) { // If it exists, hide the button document.getElementById('enable').style.display = 'none'; } else { // If it doesn't exist, add event listener to the button document.getElementById('enable').addEventListener('click', () => { askForPermission(); localStorage.setItem('enable', 'true'); document.getElementById('enable').style.display = 'none'; }); } // Function to ask for notification permission function askForPermission() { Notification.requestPermission().then((permission) => { if (permission === 'granted') { // When permission is granted, register the service worker registerServiceWorker(); } else { console.log("Notification permission denied!"); } }).catch(function(error) { console.error('Error requesting notification permission:', error); }); } // Function to register the service worker function registerServiceWorker() { console.log('test'); navigator.serviceWorker.ready.then((sw) => { sw.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: "BFSaQyz3LSete1tR6WhZFXbvC2WfWRXDfeqA0j7sm2GesTOoruXKh9QMWC1XRsG25L4ZTqhjze0HnhIGEpKsIs8" }).then((subscription) => { console.log('Subscription successful:', subscription); saveSub(JSON.stringify(subscription)); }).catch(function(error) { console.error('Error subscribing to push notifications:', error); }); }).catch(function(error) { console.error('Error retrieving service worker:', error); }); } // Function to save the subscription on the server function saveSub(sub) { $.ajax({ type: 'post', url: '{{ URL('save-push-notification-sub') }}', data: { '_token': "{{ csrf_token() }}", 'sub': sub, }, success: function(data) { console.log('Subscription saved on server successfully:', data); }, error: function(error) { console.error('Error saving subscription on server:', error); } }); } </script>
以下是针对部署后Service Worker ready状态无法触发的常见问题及解决办法:
HTTPS环境检查
Service Worker的ready状态及Push API仅支持HTTPS环境(localhost除外)。确认服务器已配置有效SSL证书,网站通过HTTPS协议访问。修正Service Worker路径
原代码中URL::asset('public/service-worker.js')存在路径冗余,Laravel的asset()方法默认指向public目录,应改为{{ asset('service-worker.js') }}。同时确认服务器public目录下确实存在该文件。调整Service Worker作用域
Service Worker的默认作用域是其所在目录,若文件不在网站根目录,可能导致ready状态无法触发。建议将service-worker.js放在public根目录下,确保注册路径为根路径。优化ready状态监听逻辑
直接调用navigator.serviceWorker.ready可能因Service Worker未完全激活而停滞,可修改为先获取已注册实例再监听ready状态:function registerServiceWorker() { console.log('test'); navigator.serviceWorker.getRegistration().then(registration => { if (registration) { registration.ready.then((sw) => { sw.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array("BFSaQyz3LSete1tR6WhZFXbvC2WfWRXDfeqA0j7sm2GesTOoruXKh9QMWC1XRsG25L4ZTqhjze0HnhIGEpKsIs8") }).then((subscription) => { console.log('Subscription successful:', subscription); saveSub(JSON.stringify(subscription)); }).catch(function(error) { console.error('Error subscribing to push notifications:', error); }); }).catch(function(error) { console.error('Error retrieving service worker ready state:', error); }); } else { console.error('No service worker registration found'); } }).catch(err => console.error('Failed to get registration:', err)); }修复Application Server Key格式
Push API要求applicationServerKey为Uint8Array格式,需添加转换函数:function urlBase64ToUint8Array(base64String) { const padding = '='.repeat((4 - base64String.length % 4) % 4); const base64 = (base64String + padding) .replace(/-/g, '+') .replace(/_/g, '/'); const rawData = window.atob(base64); return Uint8Array.from([...rawData].map(char => char.charCodeAt(0))); }调用时将原字符串替换为
urlBase64ToUint8Array("你的密钥字符串")。清除浏览器缓存
服务器可能缓存了旧版Service Worker文件,导致新代码无法生效。可在文件名后添加版本号(如service-worker-v1.js),或配置服务器禁止缓存Service Worker文件。
内容的提问来源于stack exchange,提问作者IBRA

