简体   繁体   中英

Rejected Fetch Promise: access to response text

I'm using the Fetch API to load some JSON. Therefore, I use .json() on the response stream and also the optional second function argument ( onRejected ) in .then() , which has only one argument, the rejection reason.

If something goes wrong (like the response being no valid JSON), I want access to the raw response text to have some meaningful error log or to further process the unexpected response.

Consider this simplified snippet:

fetch('api.php')
.then(
    response => { return response.json(); }
)
.then(
    json => { /* useful fulfillment value, a JSON object */ },
    reason => { /* string message only */ }
);

If the API responds with something other than valid JSON, it will reject with the following reason:

SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

While this is a perfectly clear error message, it lacks a dump of what actually caused the error.

I considered using .text() and then trying to parse the JSON myself, but that would somewhat contravene the purpose of .json() .

Is there a reasonable way to access the response text if stream-reading is rejected?

You can check the content type:

  var contentType = response.headers.get("content-type");
  if(contentType && contentType.indexOf("application/json") !== -1) {
       response => { return response.json(); }
  }
  else{
       response => { return response.text(); }
  }

If you want to get the response in the rejection callback you can do something like this

  response => { 
          var text = '';
          try{
              text= response.json(); 
          }
          catch (e if e instanceof SyntaxError) {
             text = response.text();
          } 
          return text;
  }

Lets say this is nasty but could solve the problem:

let res;
fetch('api.php')
.then(
    response => { res = response; return response.json(); }
)
.then(
    json => { /* useful fulfillment value, a JSON object */ },
    reason => { /* use res variable */ }
);

If the response is certain to have a body then read the text using the response.text() method (as shown in other answers or elsewhere: MDN , Google Web ) then parse it yourself before or after any additional conditions or checks (is it JSON? check then use JSON.parse).

Using the body is not an effective technique for generally handling errors. What happens in cases where the API doesn't include a body, or it's malformed, or the request fails entirely? Instead look at the response.statusText (eg 'Not found.'), response.status (eg 404) and other headers. Or in cases where the fetch fails the response will be an Error object with an error.message and error.stack . If you own the API and require more sophisticated/predictable messaging consider adding custom headers like 'special-message' and retrieve it with something like if(response.headers) response.headers.get('special-message') .

Only work with the body once these other scenarios are not an issue to have a little more predictability. The above headers are also available before any streaming complete to further simplify and improve responsiveness and response handling.

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