CodeIgniter中实现关闭标签页/浏览器时自动登出用户的问题
Hey there, let's fix that tab-close logout problem you're hitting in Chrome 71+. I'll break down why your current code isn't working and walk you through a reliable solution.
Why Your Current beforeunload Code Fails
Modern browsers (including Chrome 71+) have tightened restrictions on the beforeunload event:
- Returning a confirmation message only triggers a user prompt if the page has unsaved changes or user interaction—it doesn't automatically run your logout logic.
- Even if you tried to send an async logout request in this event, browsers often cancel pending network requests when the page unloads, so the request might never reach your server.
Step-by-Step Fix
1. Use navigator.sendBeacon() for Reliable Logout Requests
The sendBeacon() API is designed specifically for sending data during page unload. It doesn't block the page from closing, and browsers guarantee they'll try to complete the request even after the page is gone.
Replace your existing beforeunload handler with this:
window.addEventListener('beforeunload', function(e) { // Send logout request using Beacon API const logoutUrl = "<?php echo base_url('staff/staff_logout'); ?>"; navigator.sendBeacon(logoutUrl); // Optional: Show a confirmation prompt (only appears if user has interacted with the page) const confirmationMessage = "Warning: Closing this tab will log you out. Are you sure you want to continue?"; e.returnValue = confirmationMessage; return confirmationMessage; });
2. Avoid Logging Out on Internal Navigation (Optional)
If you don't want users to be logged out when they refresh the page or click internal links, add logic to distinguish those actions from tab closure:
let isInternalNavigation = false; // Mark internal link clicks document.addEventListener('click', function(e) { const link = e.target.closest('a'); if (link && link.host === window.location.host) { isInternalNavigation = true; } }); // Mark form submissions document.addEventListener('submit', function() { isInternalNavigation = true; }); window.addEventListener('beforeunload', function(e) { if (!isInternalNavigation) { const logoutUrl = "<?php echo base_url('staff/staff_logout'); ?>"; navigator.sendBeacon(logoutUrl); } const confirmationMessage = "Warning: Leaving this page will log you out. Are you sure you want to continue?"; e.returnValue = confirmationMessage; return confirmationMessage; });
3. Verify Your Logout Endpoint
Make sure your staff_logout method properly destroys the session:
public function staff_logout() { $this->session->sess_destroy(); redirect('staff/login'); }
Your existing $config['sess_expiration'] = 0 setting is still good for handling browser-wide closure—this tab-close logic complements it.
Testing Tips
- Don't test with Chrome DevTools open—browsers alter
beforeunloadbehavior when dev tools are active, which might prevent the beacon request from sending. - Add a log entry in your
staff_logoutmethod to confirm the server is receiving the request.
Bonus: Clean Up Your Idle Logout Code
While we're at it, let's make your 10-minute idle logout more robust (avoid string-based setInterval calls which can cause scope issues):
let idleTimer = null; function startIdleTimer() { idleTimer = setInterval(auto_logout, 300000); // Pass function reference directly } function resetIdleTimer() { if (idleTimer) { clearInterval(idleTimer); startIdleTimer(); } } function auto_logout() { window.location.href = "<?php echo base_url('staff/staff_logout'); ?>"; } // Listen for user interactions to reset the timer document.addEventListener('mousemove', resetIdleTimer); document.addEventListener('keydown', resetIdleTimer); document.addEventListener('click', resetIdleTimer);
内容的提问来源于stack exchange,提问作者Alek Stephanok

