Javascript 在HTTP错误422的情况下,如何使用fetch获取响应正文?

Javascript 在HTTP错误422的情况下,如何使用fetch获取响应正文?,javascript,reactjs,http,error-handling,fetch,Javascript,Reactjs,Http,Error Handling,Fetch,我在后端有一个API,它在调用成功的情况下发送状态201,如果 提交数据中的任何错误都会发送状态422(不可处理实体),json响应如下: { "error": "Some error text here explaining the error" } 此外,它还发送404,以防API由于某种原因无法在后端工作 在前端,我使用以下代码获取响应,并根据响应状态代码执行成功或错误回调: fetch(“api\u url\u此处”{ 方法:“这里的一些方

我在后端有一个API,它在调用成功的情况下发送状态
201
,如果 提交数据中的任何错误都会发送状态
422
(不可处理实体),json响应如下:

{
  "error": "Some error text here explaining the error"
}
此外,它还发送
404
,以防API由于某种原因无法在后端工作

在前端,我使用以下代码获取响应,并根据响应状态代码执行成功或错误回调:

fetch(“api\u url\u此处”{
方法:“这里的一些方法”,
凭据:“相同来源”,
标题:{
“内容类型”:“应用程序/json;字符集=UTF-8”,
“X-CSRF-Token”:“这里有一些Token”
}
})
.然后(检查状态)
.then(函数json(响应){
返回response.json()
})
.然后(功能(resp){
成功回调(resp)
})
.catch(函数(错误){
errorCallback(错误);
});
//上面使用的状态函数
检查状态=(响应)=>{
如果(response.status>=200&&response.status<300){
返回承诺。解决(响应)
}否则{
返回承诺。拒绝(新错误(响应))
}

}
简短回答

因为您假设您两次解析响应内容是不正确的。在原始代码段中,当满足错误条件时,将跳过
then(checkStatus)
之后的
then

长答案

一般来说,结构良好的项目包括:

  • 在将来某个时候履行或拒绝的承诺
  • 然后
    仅在履行承诺时运行的处理程序
  • catch
    仅在拒绝承诺时运行的处理程序
  • 最终
    (可选)在承诺结算时运行(在2或3中)
  • 2和3中的每个处理程序都返回启用链接的承诺

    接下来,fetchapi的
    fetch
    方法,因此不管响应的
    状态如何,都会调用第一个
    then
    方法。在您的第一个处理程序中,回调将返回已履行或已拒绝的承诺

    如果实现,它将控制权传递给链中的下一个
    然后
    方法调用,您可以通过调用响应上的
    JSON
    方法来提取JSON,然后将该方法作为承诺值传递给最后一个
    然后
    方法以在
    成功回调中使用

    如果被拒绝,控件将传递给
    catch
    方法调用,该方法调用将接收值设置为
    newerror(response)
    的承诺,然后立即传递给
    errorCallback
    。因此,后者接收
    Error
    的实例,其值是from Fetch API的实例

    这正是您在日志中看到的:
    Error:[object Response]
    ,这是对
    Error
    实例调用
    toString
    方法的结果。第一部分是构造函数名称,第二部分是内容的字符串标记(形式为[type constructor])

    怎么办?

    由于您的API为每个可能的用例返回JSON响应(
    201
    404
    422
    ),因此将解析后的响应传递给已履行和已拒绝的承诺。另外,请注意,您在全局作用域上意外声明了
    checkStatus
    ,忽略了
    var
    const
    let
    关键字:

    //模拟响应对象
    常数res={
    现状:200,
    身体:“模仿”,
    异步json(){
    常数{
    身体
    }=这个;
    返回体;
    }
    };
    const checkStatus=异步(响应)=>{
    const parsed=wait response.json();
    常数{
    地位
    }=响应;
    如果(状态>=200&&status<300){
    返回解析;
    }
    return Promise.reject(新错误(已解析));
    };
    常数测试=()=>{
    返回检查状态(res)
    .then(console.log)
    .catch((错误)=>console.warn(错误消息))
    .最后(()=>{
    如果(资源状态===200){
    res.status=422;
    返回测试();
    }
    });
    };
    
    test()这是因为在发生错误的情况下,将跳过处理程序并执行catch处理程序,
    checkStatus
    返回拒绝的承诺,然后绕过剩余的

    这就是我重构代码的方法

    checkStatus = async (response) => {
        if (response.status >= 200 && response.status < 300) 
          return await response.json()
    
        throw await response.json()
      }
    }
    
    
    fetch("api_url_here", {
        method: 'some_method_here', 
        credentials: "same-origin",
        headers: {
          "Content-type": "application/json; charset=UTF-8",
          'X-CSRF-Token': "some_token_here"
        }
        })
      .then(checkStatus)
      .then(successCallback)
      .catch(errorCallback);
    
    checkStatus=async(响应)=>{
    如果(response.status>=200&&response.status<300)
    return wait response.json()
    抛出wait response.json()
    }
    }
    获取(“api\u url\u此处”{
    方法:“这里的一些方法”,
    凭据:“相同来源”,
    标题:{
    “内容类型”:“应用程序/json;字符集=UTF-8”,
    “X-CSRF-Token”:“这里有一些Token”
    }
    })
    .然后(检查状态)
    。然后(成功回调)
    .catch(错误回调);
    

    另外,通过使用
    async/await

    Response,可以更好地直观地查看此代码。json()是异步的,因此您可能希望使checkStatus异步并等待response@SørenEriksen是的,我理解这一点,但在checkStatus中获取响应可能不是最干净的方式。我这样做只是为了检查之前发生的事情。在您定义的checkStatus函数中,您编写了
    const parsed=response.json()。在执行此语句之前是否需要一个
    wait
    ,在checkStatus函数本身之前是否需要一个
    async
    。否则,IF语句中的
    返回Promise.resolve(已解析)
    将在解析
    response.json()
    之前运行。我是否错过了它?哦,当然,它必须与
    等待
    ,我的坏。教训是-永远不要将原始代码段用作框架:)我甚至在主要代码段中提到了“json方法返回承诺!”。此外,我代码段中的这段代码导致了问题
    return Promise.reject(新错误(已解析))。。。。将解析后的响应包装在
    新错误中
    导致它丢失json消息