获取:拒绝承诺并在状态不正确时捕获错误?

时间:2016-07-07 00:03:18

标签: javascript redux fetch-api

这就是我的目标:

import 'whatwg-fetch';

function fetchVehicle(id) {
    return dispatch => {
        return dispatch({
            type: 'FETCH_VEHICLE',
            payload: fetch(`http://swapi.co/api/vehicles/${id}/`)
                .then(status)
                .then(res => res.json())            
                .catch(error => {
                    throw(error);
                })
            });
    };
}

function status(res) {
    if (!res.ok) {
        return Promise.reject()
    }
    return res;
}
编辑:承诺不会被拒绝,这就是我想要弄清楚的。

我在Redux中使用此fetch polyfill redux-promise-middleware

6 个答案:

答案 0 :(得分:68)

Fetch promise仅在发生网络错误时拒绝TypeError。由于4xx和5xx响应不是网络错误,因此无法捕获。您需要自己抛出错误才能使用Promise#catch

fetch Response方便地提供ok ,告诉您请求是否成功。这样的事情可以解决问题:

fetch(url).then((response) => {
  if (response.ok) {
    return response.json();
  } else {
    throw new Error('Something went wrong');
  }
})
.then((responseJson) => {
  // Do something with the response
})
.catch((error) => {
  console.log(error)
});

答案 1 :(得分:8)

感谢大家的帮助,拒绝var mongodb = require('mongodb').MongoClient; module.exports= { establishConnection: function (connectionstring, databasename, queryby, queryval, callback) { var filenames=[]; var filepaths=[]; var results; mongodb.connect(connectionstring, function (err, db) { if (callback) { callback(); } if (!err) { var cursor=db.collection(databasename).find(); cursor.each(function(err,doc){ if(doc!=null) { callback(doc.filename+","+doc.filepath); } }) } else console.log("Error happened"); }); }, addvalues: function (connectionstring, databasename, filename, filepath, callback) { if (callback) { callback(); } mongodb.connect(connectionstring, function (err, db) { var collec = db.collection(databasename); if (collec != null) { db.collection('storedimages').insert({ "filename": filename, "filepath": filepath }, {w: 1}, function (err, records) { if (records != null) { console.log("Record added"); db.close(); } else console.log("Cannot add"); }); } else { console.log("Database not found! error"); } }); }, retrievevalues: function ( connectionstring, databasename, filename, filepath, callback) { if (callback) { callback(); } mongodb.connect(connectionstring, function (err, db) { var collec = db.collection(databasename); if (collec != null) { db.collection('storedimages').find({"filename":filename,"filepath":filepath},{w:1},function(err,records){ if(records!=null) { console.log("Record retrieved"); db.close(); } else console.log("Cannot retrieve"); }); } else { console.log("Database not found! error"); } }); } }` 中的承诺解决了我的问题:

.catch()

答案 2 :(得分:6)

对我来说, fny的答案确实掌握了一切。由于fetch不会引发错误,因此我们需要自己引发/处理错误。 用异步/等待发布我的解决方案。我认为它更具前瞻性和可读性

解决方案1:不抛出错误,请自行处理错误

  async _fetch(request) {
    const fetchResult = await fetch(request); //Making the req
    const result = await fetchResult.json(); // parsing the response

    if (fetchResult.ok) {
      return result; // return success object
    }


    const responseError = {
      type: 'Error',
      message: result.message || 'Something went wrong',
      data: result.data || '',
      code: result.code || '',
    };

    const error = new Error();
    error.info = responseError;

    return (error);
  }

如果遇到错误,我们将构建一个错误对象,普通的JS对象并返回它,缺点是我们需要在外部进行处理。 使用方法:

  const userSaved = await apiCall(data); // calling fetch
  if (userSaved instanceof Error) {
    debug.log('Failed saving user', userSaved); // handle error

    return;
  }
  debug.log('Success saving user', userSaved); // handle success

解决方案2:使用try / catch

引发错误
async _fetch(request) {
    const fetchResult = await fetch(request);
    const result = await fetchResult.json();

    if (fetchResult.ok) {
      return result;
    }

    const responseError = {
      type: 'Error',
      message: result.message || 'Something went wrong',
      data: result.data || '',
      code: result.code || '',
    };

    let error = new Error();
    error = { ...error, ...responseError };
    throw (error);
  }

在这里,我们抛出并创建了我们创建的错误,因为Error ctor只批准字符串,Im创建了普通的Error js对象,其用途为:

  try {
    const userSaved = await apiCall(data); // calling fetch
    debug.log('Success saving user', userSaved); // handle success
  } catch (e) {
    debug.log('Failed saving user', userSaved); // handle error
  }

解决方案3:使用客户错误

  async _fetch(request) {
    const fetchResult = await fetch(request);
    const result = await fetchResult.json();

    if (fetchResult.ok) {
      return result;
    }

    throw new ClassError(result.message, result.data, result.code);
  }

并且:

class ClassError extends Error {

  constructor(message = 'Something went wrong', data = '', code = '') {
    super();
    this.message = message;
    this.data = data;
    this.code = code;
  }

}

希望有帮助。

答案 3 :(得分:2)

我刚检查了响应对象的状态:

$promise.then( function successCallback(response) {

  console.log(response);

  if( response.status === 200 ) { ... }

});

答案 4 :(得分:1)

2021 TypeScript 答案

我所做的是编写一个采用泛型的 fetch 包装器,如果 responseok,它将自动 .json() 并输入断言结果,否则包装器抛出 response

export const fetcher = async <T>(input: RequestInfo, init?: RequestInit) => {
  const response = await fetch(input, init);

  if (!response.ok) {
    throw response;
  }

  return response.json() as Promise<T>;
};

然后我会捕捉错误并检查它们是否是 instanceof Response。这样 TypeScript 就知道 error 具有 Response 属性,例如 status statusText body headers 等,我可以为每个属性应用自定义消息4xx 5xx 状态代码。

try {
  return await fetcher<LoginResponse>("http://localhost:8080/login", {
    method: "POST",
    headers: {
      Accept: "application/json",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ email: "user@example.com", password: "passw0rd" }),
  });
} catch (error) {
  if (error instanceof Response) {
    switch (error.status) {
      case 401:
        throw new Error("Invalid login credentials");
      /* ... */
      default:
        throw new Error(`Unknown server error occured: ${error.statusText}`);
    }
  }
  throw new Error(`Something went wrong: ${error.message || error}`);
}

如果发生网络错误之类的事情,可以在 instanceof Response 检查之外使用更通用的消息来捕获它,即

throw new Error(`Something went wrong: ${error.message || error}`);

答案 5 :(得分:0)

@fny 的答案(已接受的答案)对我不起作用。 throw new Error() 没有被 .catch 接收。我的解决方案是使用构建新承诺的函数包装 fetch


function my_fetch(url, args) {
  return new Promise((resolve, reject) => {
    fetch(url, args)
    .then((response) => {
      response.text().then((body) => { 
        if (response.ok) {
          resolve(body) 
        } else {
          reject(body) 
        }
      })
    })
    .catch((error) => { reject(error) })
  })
}

现在,.catch 方法将获取所有错误和非正常返回:

my_fetch(url, args)
.then((response) => {
  // Do something with the response
})
.catch((error) => {
  // Do something with the error
})