【问题标题】:Fetch api - getting json body in both then and catch blocks for separate status codesFetch api - 在 then 和 catch 块中获取 json 主体以获取单独的状态代码
【发布时间】:2017-01-13 08:26:20
【问题描述】:

我正在使用 fetch api 来获取可能返回的 URL:

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

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

响应: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
    }
}

【问题讨论】:

标签: javascript promise es6-promise fetch-api


【解决方案1】:

response.json() 返回一个异步结果。您不会从链接到response.json().then() 中返回parseJSON 的对象。要纠正这个问题,您可以在 parseJSON 调用中返回 response.json() 承诺,并从链接到 response.json().then() 中返回包含 datastatus 的对象

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

【讨论】:

  • 您实际上可以将该函数体缩短为 return response.json().then(json =&gt; ({ data: json, status: response.status }));
  • @JaromandaX 是的,不想让 Answer 上的问题进一步复杂化
  • 看起来 OP 对箭头函数足够熟悉,甚至可以做 var parseJSON = response =&gt; response.json().then(json =&gt; ({ data: json, status: response.status }));
【解决方案2】:

这里有一个稍微不同的方法:我使用单行创建一个带有 ok、status 和 json-as-object(不是承诺)的类似响应的承诺,然后我决定如何处理这个对象。通常,如果 response.ok 为 false,我会拒绝响应,否则我仅使用 json-data 解决。网络错误/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))

【讨论】:

  • 据我所知,使用带有响应的扩展运算符不起作用,但会导致未定义。所以你的 es6 例子是错误的。你能确认一下吗?
  • @webwelten:你说得对,我不知道我为什么写这个。我相信当我编写它时它对我有用(我通常在发布之前测试代码)。但是,该代码(现在已废弃)经历了编译步骤(babel 和/或打字稿,如果我没记错的话)到旧式 JS,所以也许这就是原因。我将从答案中删除该行。
猜你喜欢
  • 2018-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-22
  • 1970-01-01
  • 2013-10-06
相关资源
最近更新 更多