Fetch api - 在 then 和 catch 块中获取 json 主体以获得单独的状态代码

Fetch api - getting json body in both then and catch blocks for separate status codes

我正在使用 fetch api 来获取可能 return:

的 URL

Response : status = 200, json body = {'user': 'abc', 'id': 1}

Response : status = 400 , json body = {'reason': 'some reason'}

Response : status = 400 , json body = {'reason': 'some other reason'}

我想创建一个单独的函数 request(),我在代码的各个部分使用它,如下所示:

    request('http://api.example.com/').then(
        // status 200 comes here
        data => // do something with data.id, data.user
    ).catch(
        // status 400, 500 comes here
        error =>  // here error.reason will give me further info, i also want to know whether status was 400 or 500 etc
    )

我无法在 200 和 400,500 之间进行拆分(我曾尝试抛出错误)。当我抛出错误时,我发现仍然很难提取 JSON 正文(用于 error.reason)。

我目前的代码如下:

import 'whatwg-fetch';

/**
 * Requests a URL, returning a promise
 */
export default function request(url, options={}) {

    console.log('sending api request, url = ' + url)

    return fetch(url, options)
        .then(checkStatus)
        .then(parseJSON)
        .then((data) => ({data}))
        .catch((err) => ({err}));
}


function checkStatus(response) {
    if (response.status >= 200 && response.status < 300) {
        return response;
    }

    const error = new Error(response.statusText);
    error.response = response;
    throw error;
}



function parseJSON(response) {
    return response.json();   // json() is a promise itself
}

我试图通过如下方式解决这个问题,方法是颠倒 .then() 调用的顺序,但不起作用

export default function request(url, options) {
    return fetch(url, options)
        .then(parseJSON)        // note that now first calling parseJSON to get not just JSON but also status. 
        .then(checkStatus)      // i.e. Inverted order of the two functions from before

        .then((data) => ({data}))
        .catch((err) => ({err}));
}

function checkStatus({data, status}) {

    if (status >= 200 && status < 300) {
        return data;
    }
    else {
        // const error = new Error(response.statusText);
        const error = new Error("Something went wrong");
        // error.response = response;
        error.data = data;

        throw error;
    }

}

function parseJSON(response) {
    let jsonBody

    response.json().then(json => {
        jsonBody = json                 // this does not help, i thought it will make jsonBody fill up, but seems its in a diff thread
    })              

    return {
        data: jsonBody,
        status: response.status     // my aim is to send a whole dict with status and data to send it to checkStatus, but this does not work
    }
}

response.json() returns 一个异步结果。您没有 return 从链接到 response.json().then()parseJSON 处的对象。要更正该问题,您可以 return response.json() 承诺在 parseJSON 调用和 return 包含 datastatus 的对象 .then()链接到 response.json()

function parseJSON(response) {
    return response.json().then(json => {
          return {
                   data: json,
                   status: response.status  
                 }
    })         
}  

这里的方法略有不同:使用单行代码,我创建了一个类似响应的承诺,其中包含 ok、status 和 json-as-object(不是承诺),然后我决定如何处理它目的。通常,如果 response.ok 为假,我会拒绝响应,否则我只使用 json 数据进行解析。网络 errors/json-parse-errors 照常被拒绝。

fetch(url, options)
    .then(r => r.json().then(json => ({ok: r.ok, status: r.status, json})))
    .then( r => r.ok ? r.json: Promise.reject(r))