PHP Server-Sent Events连接无法关闭?技术求助
Let's break down why your SSE connection might be refusing to close, and walk through actionable fixes tailored to your code.
First: Fix a Critical JS Bug in Your Event Binding
Looking at your JavaScript code, you're assigning onmessage to the EventSource constructor instead of your actual myEventSource instance. This is a common mistake that breaks both event handling and your ability to reference the connection later to close it.
Here's the corrected JS code:
var myEventSource; if (typeof(EventSource) !== "undefined" && !myJsIssetFunction(viridem.serverSideEvent.config.reindexProcessingEvent)) { myEventSource = new EventSource('/my/url/path.php?event=myevent'); // Bind to the INSTANCE, not the EventSource constructor myEventSource.onmessage = function(e) { // Handle your e.data here console.log('Received SSE data:', e.data); }; // Add error handling to catch connection issues myEventSource.onerror = function(error) { console.error('SSE connection error:', error); // Auto-close on critical errors this.close(); }; } // Create a dedicated function to close the connection function closeSSEConnection() { // Only close if the connection exists and is open if (myEventSource && myEventSource.readyState !== EventSource.CLOSED) { myEventSource.close(); myEventSource = null; // Clear the reference to aid garbage collection console.log('SSE connection successfully closed'); } }
Call closeSSEConnection() whenever you need to terminate the connection (e.g., a button click, after a task completes, or when navigating away from the page).
Second: Ensure Your PHP Backend Properly Terminates the Connection
If your PHP script doesn't exit cleanly or fails to send proper signals, the connection might hang open. Here's how to optimize your PHP code:
<?php header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); header('Connection: keep-alive'); $event = $_GET['event'] ?? ''; if ($event === 'myevent') { // Your existing logic to send data echo "data: Processing update...\n\n"; flush(); ob_flush(); // When you want to close the connection from the server: $taskCompleted = false; // Replace with your actual completion check if ($taskCompleted) { // Send a custom "close" event to notify the frontend echo "event: close\n"; echo "data: Server closing connection\n\n"; flush(); ob_flush(); // Exit immediately to terminate the connection exit(); } } ?>
Then, add a listener in your JS to catch this server-initiated close signal:
myEventSource.addEventListener('close', function(e) { closeSSEConnection(); });
Common Pitfalls to Avoid
- Don't rely on browser auto-close: Browsers might not immediately close SSE connections when navigating away, so always explicitly call
close(). - Prevent cached connections: Add a unique timestamp to your SSE URL (e.g.,
'/my/url/path.php?event=myevent&t=' + Date.now()) to avoid stale connections from browser caching. - Check readyState: Before calling
close(), verify the connection is in theOPENstate (myEventSource.readyState === EventSource.OPEN).
内容的提问来源于stack exchange,提问作者Jordan Daigle

