简体   繁体   中英

Why triggering `catch` in `fetch` depends on how I return a response in first `then`?

Consider this code:

fetch('https://www.reddit.com/r/javascript/json')
  .then(res => res.text())
  .then(() => {
    console.log('SUCCESS');
  })
  .catch(err => {
    console.log('FAIL');
  })

It's intentionally a wrong route and it returns an error with code 404. But nevertheless, the SUCCESS case is triggering.

However, if I replace res => res.text() with res => res.json() it catch FAIL as it supposed to be.

Moreover, placing absolutely wrong URL (I mean non-existing server) leads to correct cathing FAIL even with res.text() .

I find this behavior a bit strange and tricky and would be grateful for some clarification.

PS I know, that here may help this precaution: if (!res.ok) throw new Error(); , just curious why it's going this way.

It's intentionally a wrong route and it returns an error with code 404. But nevertheless, the SUCCESS case is triggering.

This is by design. The fetch call only promises to make the request and return a response - any response. It will reject only in case of network problems, such as your non-existing server when you changed the domain.

The status code or body content do not matter in determining whether it's valid HTTP response. To check whether it's HTTP status is successful, you have to test res.ok as you already stated.

However, if I replace res => res.text() with res => res.json() it catch FAIL as it supposed to be.

Yes, but that's not because the request failed. It throws because your response body is not valid JSON - which it could quite well have be even with 404.

Short answer is your Promise is throwing an error on res.json()

Long answer (explanation)

Your initial http call succeeds and hence executes the 'success' promise

  • This is because the url exists and responds with successful status code and returns an html page represented by string/text
  • the response it returns is just a textual representation of a page that happens to display the text 'page not found', but your call status to get this page is NOT 404, it is in fact a 200, or you wouldn't be able to see the page...... (quite a mind bender)

BUT... even though your call is actually successful, when an unhandled error is thrown anywhere in the Promise you will ALWAYS trigger the 'fail' promise (the catch ), that is just how a promise works.

Now.... Basically that uri returns a textual representation of an html page, so calling res.text() is successful, BUT when you call res.json() on 'text' data it throws an error because the response is not json, and that error bubbles up and eventually is caught by the catch of the promise. If you want json you must first know the data type you expect from your response and then convert to what you want.

Lesson Here is know your return type so you know what to expect and code for, it just doesn't make sense to call a uri and not know what type of data it returns.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM