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

Posted

技术标签:

【中文标题】Fetch api - 在 then 和 catch 块中获取 json 主体以获取单独的状态代码【英文标题】:Fetch api - getting json body in both then and catch blocks for separate status codes 【发布时间】: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
    

【问题讨论】:

错误出现在 .then 的第二个回调中 -> request('http://api.example.com/').then( function(data) //success call back, i.e 200 , function( jqXHR, textStatus, errorThrown) // error call back. Check the status code here ); this does not help - 该代码的问题是 Promises 不会使异步代码同步(代码假定它们会同步) 与Cleanest way to handle custom errors with fetch & ES6 promise 或fetch: Reject promise with JSON error object 重复? 【参考方案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,所以也许这就是原因。我将从答案中删除该行。

以上是关于Fetch api - 在 then 和 catch 块中获取 json 主体以获取单独的状态代码的主要内容,如果未能解决你的问题,请参考以下文章

基于Promise规范的fetch API的使用

Fetch API

fetch和axios获取数据

使用 fetch() 在 React 中进行分页

[Javascript] Fetch API

在 javascript 中的另一个 fetch 中使用 fetch