如何用JavaScript的fetch方法捕获401错误并实现Token重试
Great question! One common gotcha with fetch() is that it doesn’t automatically reject promises for HTTP error status codes like 401—you have to explicitly check the response status in your handler. Here’s a practical way to implement token refresh and request retry for your scenario:
Step-by-Step Implementation
First, let’s refactor your code to include retry logic. We’ll create a reusable helper function to keep things clean:
// Helper function to handle authenticated requests with token refresh async function fetchWithAuth(url, options = {}) { // Initialize headers with your default values const headers = new Headers({ "Accept": "application/json", "Content-Type": "application/json", ...this.defaultRequestHeaders, // Merge your existing default headers ...options.headers // Allow overriding with request-specific headers }); // Add current auth token to headers (replace with your token storage) const currentToken = localStorage.getItem('accessToken'); if (currentToken) { headers.set('Authorization', `Bearer ${currentToken}`); } // Create the initial request const initialRequest = new Request(url.toString(), { headers, method: "get", mode: "cors", ...options }); try { let response = await fetch(initialRequest); // Check if we received a 401 Unauthorized if (response.status === 401) { // 1. Fetch a new token from your token endpoint const refreshResponse = await fetch('/api/token-refresh', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ refreshToken: localStorage.getItem('refreshToken') // Use your refresh token }) }); if (!refreshResponse.ok) { // Token refresh failed—redirect to login or handle error throw new Error('Refresh token invalid. Please log in again.'); } const newTokenData = await refreshResponse.json(); const newAccessToken = newTokenData.accessToken; // 2. Update stored token for future requests localStorage.setItem('accessToken', newAccessToken); // 3. Retry the original request with the new token const retryRequest = new Request(initialRequest, { headers: new Headers(initialRequest.headers) // Copy original headers }); retryRequest.headers.set('Authorization', `Bearer ${newAccessToken}`); response = await fetch(retryRequest); } // Return the final response (original or retried) return response; } catch (error) { console.error('Request failed:', error); throw error; // Re-throw so the caller can handle the error } } // Usage in your code fetchWithAuth(yourUrl) .then(response => { if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return response.json(); }) .then(data => { // Your logic to handle the API data console.log('Fetched data:', data); }) .catch(error => { // Handle errors (e.g., show login prompt if token refresh failed) alert(error.message); });
Important Considerations
- Prevent Infinite Loops: Add a retry limit (e.g., only retry once) to avoid looping if the retried request still returns 401. You can modify the helper function to accept a
retryCountparameter. - Secure Token Storage: Use
localStoragewith caution (risk of XSS attacks). For better security, consider using HttpOnly cookies for refresh tokens. - Handle Edge Cases: If the token refresh endpoint is down or returns an error, redirect the user to the login page instead of retrying.
- Reuse Request Objects: When retrying, create a new
Requestinstance from the original to avoid mutating the initial headers.
内容的提问来源于stack exchange,提问作者Vikrant Singh
相关产品推荐
相关产品推荐

