Estoy usando Promise.allSettled para llamar a una matriz de URL y necesito capturar el código de respuesta de la(s) solicitud(es) de la(s) promesa(s) rechazada(s). Usar el valor de result.reason proporcionado por Promise.allSettled no es lo suficientemente preciso para evaluar el motivo del rechazo de la promesa. Necesito el código de respuesta de solicitud (400, 500, 429, etc.).
Tengo hasta ahora lo siguiente:
var response = await Promise.allSettled(urls.map(url => fetch(url))) .then(results => { var data = []; results.forEach((result, num) => { var item = { 'req_url': urls[num], 'result': result.status, 'result_details': result }; data.push(item); }); return data; });¿Cómo podría capturar el código de respuesta de la solicitud de la promesa rechazada y agregarlo como una propiedad dentro de la matriz devuelta? La matriz devuelta debería verse idealmente así:
[{ 'req_url': 'https://myurl.xyz/a', 'req_status_code': 400, 'result': 'rejected', 'result_details': { 'status': 'rejected', 'message': 'TypeError: Failed to fetch at <anonymous>:1:876' } }, { 'req_url': 'https://myurl.xyz/b', 'req_status_code': 419, 'result': 'rejected', 'result_details': { 'status': 'rejected', 'message': 'TypeError: Failed to fetch at <anonymous>:1:890' } }, { 'req_url': 'https://myurl.xyz/c', 'req_status_code': 429, 'result': 'rejected', 'result_details': { 'status': 'rejected', 'message': 'TypeError: Failed to fetch at <anonymous>:1:925' } }]¿Algunas ideas?
fetch no rechaza su promesa en caso de falla de HTTP, solo falla de red . (En mi opinión, una pistola de API, que escribí hace unos años en mi antiguo blog anémico). Por lo general, abordo esto envolviendo fetch en algo que rechaza en caso de falla de HTTP. También puede hacer eso y hacer que el estado de falla esté disponible en el motivo del rechazo. (Pero no es necesario que lo haga, vea más abajo).
class FetchError extends Error { constructor(status) { super(`HTTP error ${status}`); this.status = status; } } async function goFetch(url, init) { const response = await fetch(url, init); if (!response.ok) { // HTTP error throw new FetchError(response.status); } return response; } Luego, podría pasar una función async al map para manejar los errores localmente y usar Promise.all (solo porque hacerlo todo en un solo lugar es más simple que hacerlo en dos lugares con Promise.allSettled ):
const results = await Promise.all(urls.map(async url => { try { const response = await goFetch(url); // ...you might read the response body here via `text()` or `json()`, etc... return { req_url: url, result: "fulfilled", result_details: /*...you might use the response body here...*/, }; } catch (error) { return { req_url: url, result: "rejected", result_status: error.status, // Will be `undefined` if not an HTTP error message: error.message, }; } })); O puede hacerlo sin un contenedor de fetch :
const results = await Promise.all(urls.map(async url => { try { const response = await fetch(url); if (!response.ok) { // Local throw; if it weren't, I'd use Error or a subclass throw {status: response.status, message: `HTTP error ${response.status}`}; } // ...you might read the response body here via `text()` or `json()`, etc... return { req_url: url, result: "fulfilled", result_details: /*...you might use the response body here...*/, }; } catch (error) { return { req_url: url, result: "rejected", result_status: error.status, // Will be `undefined` if not an HTTP error message: error.message, }; } }));