Alas, the browsers print network error in the console if the status code is 4XX or 5XX no matter what. It is possible to filter the errors as Konrad's answer suggests, but those errors are still there (i.e. they are not suppressed, just filtered) and they reappear if you uncheck the checkbox again.
To avoid those errors, the simplest solution is not to return 4XX responses from the server, but this is kind of lying and breaking the protocol like politicians do.
The clean solution on the client side can be achieved with these steps:
1. Register a service worker to intercept background requests
navigator.serviceWorker.register("noerr.js").then(_=> navigator.serviceWorker.controller
? window.dispatchEvent(new CustomEvent("swready")) // normal reload
: navigator.serviceWorker.ready.then(_=> location.reload()) // first load or Ctrl+F5
);
Suppressing works since the custom swready
event.
2. Replace the 4XX and 5XX responses in the service worker
The noerr.js service worker could be written like this:
self.addEventListener('install', e => {
self.skipWaiting(); // update even if other tabs are open in the browser
});
const proxyResponse = orig => orig.status<400 ? orig : new Response(null, {
status: 202,
statusText: "Accepted",
headers: new Headers({
"Status": orig.status,
"StatusText": orig.statusText
})
});
self.addEventListener('fetch', e => e.respondWith(
fetch(e.request).then(proxyResponse)
));
If the server responds 4XX or 5XX, the SW intercepts the request and returns 202 Accepted status code instead in accordance to the standard:
202 Accepted response status code indicates that the request has been accepted for processing, but the processing has not been completed; in fact, processing may not have started yet. The request might or might not eventually be acted upon, as it might be disallowed when processing actually takes place. 202 is non-committal, meaning that there is no way for the HTTP to later send an asynchronous response indicating the outcome of processing the request. It is intended for cases where another process or server handles the request, or for batch processing.
The process mentioned in the quote is our ServiceWorker which returns the original HTTP status code in the Status
header.
Example
window.addEventListener("swready", _=> {
// suppressing network errors works since now
fetch("nonexistent.html").then(r =>
r.headers.get("Status")==404 && console.log("Server says 404")
// no error appears in browser console
)
});
Now instead of console.log, the correct approach is to throw
in case when the response is considered errorneous, and optionally catch it later (uncaught exceptions promote to console error).
Seamless solution
To achieve this, we can write a fetch2
function that acts like fetch(), but doesn't write console errors on 4XX and 5XX:
const fetch2 = (req, opt) => fetch(req, opt).then(res =>
res.status!=202 ? res : new Response(null, {
status: res.headers.get("Status"),
statusText: res.headers.get("StatusText"),
headers: res.headers
})
);
// receives the response body or false if not ok
// called on any response including 4XX or 5XX
function responseHandler(body) { ... }
// called when the server does not respond
// or if the responseHandler throws
function serverError(errorEvent) { ... }
// never generates console.error
fetch2("nonexistent.html")
.then(r => r.ok && r.text())
.then(responseHandler)
.catch(serverError)
window.onerror
To clarify your question, there is window.onerror. It is not fired when the response code is 4XX or 5XX, since it is still a valid response, not error. Error is fired only if the server doesn't respond.
console.clear
console.clear() is not the right approach, since it clears all the console notes, not just network errors. In my use case, I wanted to ping the server every minute to check if it is currently available. It was daunting to debug it: to browse through thousands of console errors from the ping and look for real errors.