that ETIMEDOUT error can be caused from a few things, one of the most common is the node.js default timeout to resolve a domain IP.... it apparently can also be caused by IPs that resolve to both IPv4 and IPv6. Normally the solution would be export NODE_OPTIONS="--network-family-autoselection-attempt-timeout=500", maybe give that a try on the server? sometimes I've seen this solved by disabling IPv6 outright, or forcing IPv4 priority with node --dns-result-order=ipv4first or
import dnsPromises from 'node:dns/promises';
dnsPromises.setDefaultResultOrder('ipv4first');
I'm a bit out of my depth when it comes to network stuff, but I found
this rather interesting. there's this SO page where the person had to add host: url to the request options:
const options =
{
host: 'retool.bxlck.com',
headers: { 'x-ms-client-id': client_id }
}
//url to get lat/long
let url = 'https://retool.bxlck.com/api/embed-url/external-user'
//make req
let res = await axios.get(url, options)
since it seems to reset itself if you wait, you could try implementing axios-retry:
import axios from 'axios';
import axiosRetry from 'axios-retry';
const axiosInstance = axios.create({
baseURL: 'https://your-api-url.com',
timeout: 10000,
});
// setup axios-retry
axiosRetry(axiosInstance, {
retries: 3,
retryDelay: axiosRetry.exponentialDelay,
retryCondition: (error) => {
// Don't retry on 401s. Let the interceptor handle it.
return error.response.status !== 401 && axiosRetry.isNetworkOrIdempotentRequestError(error);
},
onRetry: (retryCount, error, requestConfig) => {
console.log(`Retrying request (attempt ${retryCount}): ${requestConfig.url}`);
}
});
// it looks like you already implemented logging, but just incase
axios.interceptors.response.use(
(response) => {
console.log('Request successful:', response);
return response;
},
(error) => {
console.error('Request failed:', error);
const originalRequest = error.config;
const status = error.response ? error.response.status : null
if(status === 401 && !originalRequest._retry){
originalRequest._retry = true;
try{
const newToken = await refreshToken();
originalRequest.headers['Authorization'] = `Bearer ${newToken}`;
return axiosInstance(originalRequest);
} catch (refreshError) {
// Handle token refresh failure (e.g., redirect to login)
return Promise.reject(error); // Or handle the error as needed
}
}
return Promise.reject(error);
}
);
async function refreshToken() {
// Implement your token refresh logic here. This could involve
// making another API call to get a new access token using a refresh token.
// For example:
// const refreshResponse = await axios.post('/api/refresh-token', { refreshToken });
// return refreshResponse.data.accessToken;
// Or throw an error if refresh token is also invalid
return 'new-access-token'; // Replace with the actual token
}
or u could use axios-auth-refresh to handle token refresh instead of making axios-retry handle it
import axios from 'axios';
import axiosRetry from 'axios-retry';
import createAuthRefreshInterceptor from 'axios-auth-refresh';
// Function that will be called to refresh authorization
const refreshAuthLogic = (failedRequest) =>
axios.post('https://www.example.com/auth/token/refresh', {
skipAuthRefresh: true
}).then((tokenRefreshResponse) => {
localStorage.setItem('token', tokenRefreshResponse.data.token);
failedRequest.response.config.headers['Authorization'] = 'Bearer ' + tokenRefreshResponse.data.token;
return Promise.resolve();
});
const axiosInstance = axios.create({
baseURL: 'https://your-api-url.com',
timeout: 10000,
});
// setup axios auth refresh interceptor
createAuthRefreshInterceptor(axiosInstance , refreshAuthLogic, {
statusCodes: [401, 403]
});
// setup axios-retry
axiosRetry(axiosInstance, {
retries: 3,
retryDelay: axiosRetry.exponentialDelay,
retryCondition: (error) => {
// Don't retry on 401s. Let the interceptor handle it.
return error.response.status !== 401 && axiosRetry.isNetworkOrIdempotentRequestError(error);
},
onRetry: (retryCount, error, requestConfig) => {
console.log(`Retrying request (attempt ${retryCount}): ${requestConfig.url}`);
}
});