ESP822设备Web页面在Safari中意外重载问题求助
Hi Milan, sorry to hear Safari is messing up the smooth auto-update flow for your weight sensor device's web interface! Let's break down what's likely happening and get this fixed for cross-browser compatibility.
Why This Might Be Happening in Safari
There are two common culprits here:
- Aggressive GET Request Caching: Safari has stricter caching rules for GET requests than other browsers. If your
/calcendpoint returns the same content repeatedly, Safari might skip making a new request and use cached data—this can lead to unexpected rendering behavior, including accidental page reloads. - innerHTML Parsing Quirks: When replacing
innerHTMLwith full HTML fragments (especially if your/calcendpoint returns complete page structure like<html>or<body>tags), Safari can sometimes misinterpret this as a full page load and trigger a reload. It's also riskier for security and rendering consistency.
Step-by-Step Fixes
Let's adjust your code to address both issues, plus add some robustness for cross-browser support.
1. Add Anti-Caching to Your Request
Append a unique timestamp to your GET URL to ensure Safari never uses cached data:
xhttp.open("GET", `/calc?_=${new Date().getTime()}`, true);
The _= parameter with a timestamp forces the browser to treat every request as unique, bypassing cache.
2. Replace InnerHTML with Safer DOM Manipulation
Instead of directly overwriting innerHTML, use replaceChildren (supported in all modern browsers, including Safari) to update the container's content. This avoids unexpected HTML parsing side effects:
setInterval(loadDoc, 300); function loadDoc() { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { const targetContainer = document.getElementById("webpage"); // Create a temporary div to parse the response safely const tempDiv = document.createElement('div'); tempDiv.innerHTML = this.responseText; // Replace the container's children with the parsed content targetContainer.replaceChildren(...tempDiv.children); } }; // Add anti-cache timestamp xhttp.open("GET", `/calc?_=${new Date().getTime()}`, true); xhttp.send(); }
3. Verify Your /calc Endpoint Output
Double-check that the /calc endpoint returns only the content fragment you want to update, not a full HTML document. For example, if you're displaying weight data, return something like <p>Current Weight: 12.5kg</p> instead of a complete <html><body>...</body></html> structure. Returning full page markup is the #1 cause of Safari triggering unintended reloads when using innerHTML.
Bonus: Modernize with Fetch API (Optional)
If you want cleaner, more modern code (with built-in error handling), replace XHR with the Fetch API—this works seamlessly in Safari too:
setInterval(loadDoc, 300); async function loadDoc() { try { const response = await fetch(`/calc?_=${new Date().getTime()}`); if (!response.ok) throw new Error("Failed to fetch data"); const content = await response.text(); const targetContainer = document.getElementById("webpage"); const tempDiv = document.createElement('div'); tempDiv.innerHTML = content; targetContainer.replaceChildren(...tempDiv.children); } catch (err) { console.error("Error updating data:", err); } }
Final Checks
- Open Safari's Developer Tools (enable via Safari > Settings > Advanced > Show Develop menu) and check the Console for any errors—unhandled JS errors can sometimes trigger page reloads.
- Ensure your
#webpageelement is a standard container like a<div>(not<body>or<html>)—replacing innerHTML on root elements is risky in Safari.
These changes should eliminate the Safari page reload issue while keeping your auto-update functionality working across all browsers.
内容的提问来源于stack exchange,提问作者Milan H

