Estoy buscando una forma genérica de reproducir una búsqueda si recibo una respuesta 401.
Mi aplicación es un SPA que usa OIDC. Nuestros desarrolladores frontend utilizan fetch y un ServieWorker inyecta el access_token en la solicitud de AJAX antes de enviar la solicitud a las API. Hay ocasiones en las que se produce una fetch pero access_token de acceso ha caducado. Cuando eso suceda, quiero usar refresh_token para obtener un nuevo access_token y luego reproducir el fetch , devolviendo el fetch reproducido en Promise. Idealmente, esto sería algo que los desarrolladores frontend ni siquiera sabrían que está sucediendo.
Lo que significa que un desarrollador de UI codificará algo como lo que se muestra a continuación (recuerde, el access_token se inyecta a través de ServiceWorker):
fetch("https://backend.api/user/get/1") .then(resp => { console.log("user information is XYZ. Raw response:", resp); })Cuando realmente lo que está sucediendo en el fondo es:
[Initial request] > [Expired token response] > [Request new token] > [Initial request replayed] Experimenté anulando el método de fetch con lo que se muestra a continuación, pero no puedo encontrar una forma genérica de recrear/clonar la fetch original:
window.fetch = new Proxy(window.fetch, { apply(fetch, that, args) { // Forward function call to the original fetch const result = fetch.apply(that, args); // Do whatever you want with the resulting Promise result.then(resp => { if(resp.status == 400 || resp.status == 401) { let rt = getRefreshToken(); return fetch("https://idaas.provider/get/new/token", { "method": "POST", "body": new URLSearchParams({ grant_type: "refresh_token", refresh_token: rt, client_id: client_id_str }) }); } }).then(resp => { let new_token = resp.new_token; send_new_token_to_service_worker(new_token); return new_token }).then(tok => { // How do I replay the original request? }) return result; } });El objetivo es simplificar lo que los desarrolladores de UI deben manejar. Quiero que se centren en UX y que este tipo de manejo de errores se realice en segundo plano.
Nota: si es necesario, estaría abierto a no usar fetch y, en su lugar, utilizar un método de envoltura. Obviamente, debido al código ya escrito alrededor de fetch , el nuevo método necesitaría aceptar los mismos argumentos y producir el mismo retorno.
window.fetch = new Proxy(window.fetch, { apply(fetch, that, args) { let fetchApi = [ fetch(args.shift()) ]; let fetchToken = [ fetch("https://idaas.provider/get/new/token", { method: "POST", body: new URLSearchParams({ grant_type: "refresh_token", refresh_token: getRefreshToken(), client_id: client_id_str, }) }).then(token => send_new_token_to_service_worker(token)), ]; return Promise.allSettled(fetchApi).then(results => { let rejected = results .map(result => result.status) .includes("rejected"); if (rejected) { return Promise.all([...fetchToken, ...fetchApi]).then(results => results.at(1)); } else { return results.at(0).value; } }); }, });uso fetch("https://your-api").then(resp => resp);