StuartM
StuartM

Reputation: 6823

Javascript Fetch returns 404 occasionally

We are finding that occasionally our .fetch command is returning a 404. Even though the file exists and is hit regularly sometimes it's receiving a 404.

window.fetch('/category/somepage', {
    credentials: 'same-origin',
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(app.addAntiForgeryToken(postData))
  })
  .then(function(response) {
    if (response.ok) {
      return response.json();
    }
    throw new Error('Network response was not ok');
  })
  .then(result => {
    if (result.Status === 'OK') {
      //...
    }
  })

At the moment it is being caught with the throw new Error.

As we need this to resolve, what is the best way to force try this again until the page is hit? Should we show a button for retry or is there a way to loop this? I'm not sure why this would even throw a 404 as the file definitely exists all the time.

Upvotes: 0

Views: 1401

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074295

The classic thing to do here is to retry the operation, because network communications can be unreliable, particularly on mobile devices. But transient 404s are a different issue, and point to a problem with the web server that may need separate diagnosis. (For instance: If it's a cluster of web servers acting as a single endpoint, one of them may be misconfigured and thus not finding a resource the rest of them can find.)

But for transient failures, the classic thing is a retry:

function fetchJSONWithRetry(input, init, retries = 10) {
    return fetch(input, init)
        .then(function(response) {
            if (response.ok) {
                return response.json();
            }
            throw new Error('Network response was not ok'); // I usually use `new Error("HTTP status " + response.status)`
        })
        .catch(error => {
            if (retries <= 0) {
                throw error;
            }
            return fetchJSONWithRetry(input, init, retries - 1);
        });
}

used like this:

fetchJSONWithRetry('/category/somepage', {
    credentials: 'same-origin',
    method: 'POST',
    headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
    },
    body: JSON.stringify(app.addAntiForgeryToken(postData))
})
.then(result => {
    if (result.Status === 'OK') {
        // ...
    }
})
.catch(error => {
    // All retries failed, handle it
});

(input and init are the names used by the spec for fetch, so that's what I used above.)

Upvotes: 3

Related Questions