如何从 javascript Fetch api 获得可读的错误响应?

Posted

技术标签:

【中文标题】如何从 javascript Fetch api 获得可读的错误响应?【英文标题】:How to get Readable error response from javascript Fetch api? 【发布时间】:2017-03-17 10:25:25 【问题描述】:

我正在前端开发 Reactjs redux,后端开发 Rails api。

所以现在我使用 Fetch api 方法调用 api,但问题是我无法获得可读的错误消息,就像我在网络选项卡中得到的那样

这是我的功能

export function create_user(user,userInfoParams=) 

    return function (dispatch) 
        dispatch(update_user(user));

        return fetch(deafaultUrl + '/v1/users/',
            
                headers: 
                    'Accept': 'application/json',
                    'Content-Type': 'application/json'
                ,
                method: "POST",
                body: JSON.stringify(userInfoParams)
            )
            .then(function(response) 
                console.log(response);
                console.log(response.body);
                console.log(response.message);
                console.log(response.errors);
                console.log(response.json());
                dispatch(update_errors(response));

                if (response.status >= 400) 
                    throw new Error("Bad response from server");
                

            )
            .then(function(json)
                console.log("succeed json re");
                // We can dispatch many times!
                // Here, we update the app state with the results of the API call.

                dispatch(update_user(json));

            );


    

但是当出现错误时,我无法弄清楚如何像查看浏览器网络选项卡时那样获得可读的响应消息

这就是我遇到错误时从网络选项卡中得到的结果。

我的控制台

这是我的 Rails 代码

def create
    user = User.new(user_params)
    if user.save
      #UserMailer.account_activation(user).deliver_now
      render json: user, status: 201
    else
      render json:  errors: user.errors , status: 422
    end
  end

但我不知道如何在我的函数中获取它

谢谢!

【问题讨论】:

【参考方案1】:

由于文本隐藏在响应对象内的承诺中,因此需要像承诺一样处理才能看到它。

fetch(bla)
    .then(res => 
      if(!res.ok) 
        return res.text().then(text =>  throw new Error(text) )
       
      else 
       return res.json();
         
    )
    .catch(err => 
       console.log('caught it!',err);
    );
    

【讨论】:

是的,response.text()response.json() both return promise objects。 你会得到错误:如果你从服务器得到 400 响应,res.text 不是一个函数。为了避免它,你必须使用try... catch...函数。【参考方案2】:

您可以通过这种方式访问​​错误消息:

return fetch(deafaultUrl + '/v1/users/',
            
                headers: 
                    'Accept': 'application/json',
                    'Content-Type': 'application/json'
                ,
                method: "POST",
                body: JSON.stringify(userInfoParams)
            )
            .then(function(response) 
                console.log(response);
                console.log(response.body);
                console.log(response.message);
                console.log(response.errors);
                console.log(response.json());
                dispatch(update_errors(response));

                if (response.status >= 400) 
                    throw new Error("Bad response from server");
                

            )
            .then(function(json)
                console.log("succeed json re");
                // We can dispatch many times!
                // Here, we update the app state with the results of the API call.

                dispatch(update_user(json));

            )
            // here's the way to access the error message
            .catch(function(error) 
              console.log(error.response.data.message)
            )

;

【讨论】:

【参考方案3】:

尽管这是一个有点老的问题,但我还是要插话。

在上面的 cmets 中有这样的答案:

const fetchJSON = (...args) => 
  return fetch(...args)
    .then(res => 
      if(res.ok) 
        return res.json()
      
      return res.text().then(text => throw new Error(text))
    )

当然,您可以使用它,但要记住一件重要的事情。如果你从其余的 api 返回 json 看起来像 error: 'Something went wrong',上面显示的代码 return res.text().then(text => throw new Error(text)) 肯定会工作,但 res.text() 实际上返回字符串。是的,你猜对了!不仅字符串包含值,还包含合并在一起的键!这让你别无选择,只能以某种方式将其分开。呸!

因此,我提出了一个不同的解决方案。

fetch(`backend.com/login`, 
   method: 'POST',
   body: JSON.stringify( email, password )
 )
 .then(response => 
   if (response.ok) return response.json();
   return response.json().then(response => throw new Error(response.error))
 )
 .then(response =>  ...someAdditional code )
 .catch(error => reject(error.message))

所以让我们破解代码,尤其是第一个then

.then(response => 
       if (response.ok) return response.json();
       return response.json().then(response => throw new Error(response.error))
)

如果响应正常(即服务器返回 2xx 响应),它会返回另一个承诺 response.json(),随后在下一个 then 块中处理。

否则,我将再次调用response.json() 方法,但也会为其提供自己的then 代码块。在那里我会抛出一个新的错误。在这种情况下,括号 throw new Error(response.error) 中的响应是一个标准的 javascript 对象,因此我会从中获取错误。

如您所见,最后还有 catch 代码块,您可以在其中处理新抛出的错误。 (error.message

塔达啊!希望对您有所帮助!

我一直在寻找这个问题,并且看到了这篇文章,所以认为我的回答会在未来对某人有所帮助。

祝你有美好的一天!

马雷克

【讨论】:

【参考方案4】:

我认为你需要做这样的事情

export function create_user(user,userInfoParams=) 

  return function (dispatch) 
    dispatch(update_user(user));

    return fetch(deafaultUrl + '/v1/users/',
        
            headers: 
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            ,
            method: "POST",
            body: JSON.stringify(userInfoParams)
        )
        .then(function(response) 
            console.log(response);
            console.log(response.body);
            console.log(response.message);
            console.log(response.errors);
            console.log(response.json());
            return response.json();
        )
        .then(function(object)
          if (object.errors) 
            dispatch(update_errors(response));
            throw new Error(object.errors);
           else 
            console.log("succeed json re");
            dispatch(update_user(json));
          
        )
        .catch(function(error)
          this.setState( error )
        )
       
     

【讨论】:

【参考方案5】:

与您的答案类似,但有更多解释...我首先检查响应是否正常,然后仅在我们成功响应的情况下从 response.text() 生成错误。因此,网络错误(不是ok)仍然会生成自己的错误,而不会转换为文本。然后在下游catch 中捕获这些错误。

这是我的解决方案 - 我将核心 fetch 函数提取到一个包装函数中:

const fetchJSON = (...args) => 
  return fetch(...args)
    .then(res => 
      if(res.ok) 
        return res.json()
      
      return res.text().then(text => throw new Error(text))
    )

然后当我使用它时,我会根据需要定义如何处理我的响应和错误:

fetchJSON(url, options)
  .then((json) => 
    // do things with the response, like setting state:
    this.setState( something: json )
  )
  .catch(error => 
    // do things with the error, like logging them:
    console.error(error)
  )

【讨论】:

【参考方案6】:

首先,您需要在响应中调用 json 方法。

一个例子:

fetch(`$API_URL`, 
        method: 'post',
        headers: 
           'Accept': 'application/json',
           'Content-Type': 'application/json'
        ,
        body: JSON.stringify(userInfoParams)
    )
    .then((response) => response.json())
    .then((response) => console.log(response)) 
    .catch((err) => 
        console.log("error", err) 
    );

如果控制台日志不适合您,请告诉我。

【讨论】:

谢谢大家,但我终于找到了***.com/questions/40418981/… @VarisDarasirikul 如果您的方法与其他答案不同,请考虑回答您自己的问题,以便为阅读此问题的其他用户提供有用的资源。否则,您可以投票或接受您认为可以回答您的问题的任何答案。【参考方案7】:

您返回的变量不在response.bodyresponse.message 中。

您需要检查响应对象上的错误属性。

if(response.errors) 
    console.error(response.errors)

在这里查看https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

您实际上应该从服务器返回错误响应代码并使用 fetch API 的 .catch() 函数

【讨论】:

以上是关于如何从 javascript Fetch api 获得可读的错误响应?的主要内容,如果未能解决你的问题,请参考以下文章

javascript 如何使用fetch处理api超时

html 如何使用JavaScript Fetch API

如何使用“Fetch API”在 javascript 和 c# 之间传递数据?

Javascript Fetch API - 如何将输出作为对象保存到变量(不是承诺)

Javascript fetch 无法从 GMail API Batch 请求中读取 Multipart 响应

如何在 JavaScript 中将 Ajax 转换为 Fetch API?