fitst commit
This commit is contained in:
106
api/httpClient.ts
Normal file
106
api/httpClient.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import axios from 'axios';
|
||||
import { API_URLS, BASE_URL } from './URLs';
|
||||
|
||||
import { getToken } from '@/hooks/storage.native';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import { router } from 'expo-router';
|
||||
|
||||
const httpClient = axios.create({
|
||||
baseURL: BASE_URL,
|
||||
timeout: 60000,
|
||||
});
|
||||
|
||||
httpClient.interceptors.request.use(async (config) => {
|
||||
const token = await getToken();
|
||||
const lang = await AsyncStorage.getItem('lang');
|
||||
|
||||
config.headers['Accept-Language'] = lang;
|
||||
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
return config;
|
||||
});
|
||||
|
||||
let isRefreshing = false;
|
||||
let failedQueue: Array<{ resolve: (value: any) => void; reject: (reason?: any) => void }> = [];
|
||||
|
||||
const processQueue = (error: any = null) => {
|
||||
failedQueue.forEach((prom) => {
|
||||
if (error) {
|
||||
prom.reject(error);
|
||||
} else {
|
||||
prom.resolve(null);
|
||||
}
|
||||
});
|
||||
failedQueue = [];
|
||||
};
|
||||
|
||||
httpClient.interceptors.response.use(
|
||||
(response) => response,
|
||||
|
||||
async (error) => {
|
||||
const originalRequest = error.config;
|
||||
|
||||
// Agar 401 bo'lsa va bu refresh so'rovi bo'lmasa
|
||||
if (error.response?.status === 401 && !originalRequest._retry) {
|
||||
if (isRefreshing) {
|
||||
// Agar allaqachon refresh ketayotgan bo'lsa → kutamiz
|
||||
return new Promise((resolve, reject) => {
|
||||
failedQueue.push({ resolve, reject });
|
||||
})
|
||||
.then(() => httpClient(originalRequest))
|
||||
.catch((err) => Promise.reject(err));
|
||||
}
|
||||
|
||||
originalRequest._retry = true;
|
||||
isRefreshing = true;
|
||||
|
||||
try {
|
||||
const refresh = await AsyncStorage.getItem('refresh_token');
|
||||
|
||||
if (!refresh) {
|
||||
throw new Error('Refresh token mavjud emas');
|
||||
}
|
||||
|
||||
// Refresh token so'rovi
|
||||
const { data } = await axios.post(`${BASE_URL}${API_URLS.REFRESH}`, {
|
||||
refresh, // backend odatda { refresh } body kutadi
|
||||
});
|
||||
|
||||
// Yangi tokenlarni saqlaymiz
|
||||
await AsyncStorage.setItem('access_token', data.access);
|
||||
await AsyncStorage.setItem('refresh_token', data.refresh || refresh); // agar yangi refresh kelmasa, eskisini saqlab qolamiz
|
||||
|
||||
// Headerni yangilaymiz
|
||||
originalRequest.headers.Authorization = `Bearer ${data.access}`;
|
||||
|
||||
// Kutgan so'rovlarni qayta yuboramiz
|
||||
processQueue();
|
||||
|
||||
// Original so'rovni qayta yuboramiz
|
||||
return httpClient(originalRequest);
|
||||
} catch (refreshError) {
|
||||
console.error('Refresh token xatosi:', refreshError);
|
||||
|
||||
// Refresh muvaffaqiyatsiz bo'lsa
|
||||
processQueue(refreshError);
|
||||
|
||||
// Tokenlarni o'chirib, logout qilamiz
|
||||
await AsyncStorage.removeItem('access_token');
|
||||
await AsyncStorage.removeItem('refresh_token');
|
||||
|
||||
// Foydalanuvchini login sahifasiga yo'naltiramiz
|
||||
router.replace('/');
|
||||
} finally {
|
||||
isRefreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Boshqa xatolar uchun oddiy reject
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default httpClient;
|
||||
Reference in New Issue
Block a user