Axios
Promise based HTTP client for the browser and node.js
Categories
- Jest:Mock:Axios - jest에서 axios mockup 테스트 방법.
- axios-mock-adapter - axios 를 사용했을 때 가짜 요청을 발생시키는 라이브러리
Interceptors
client.interceptors.response.use(res => {
if (res.data.status === false) {
// Error message is retrived from the JSON body.
const error = new Error(res.data.message);
// Attach the response instance, in case we would like to access it.
error.response = res;
throw error;
}
// If the status is true, simply return back the response instance.
return res;
});
Status Code 를 에러로 만드는 방법
Using the validateStatus
config option, you can define HTTP code(s) that should throw an error.
axios.get('/user/12345', {
validateStatus: function (status) {
return status < 500; // Resolve only if the status code is less than 500
}
})
Await request
async function getUser() {
try {
const response = await axios.get('/user?ID=12345');
console.log(response);
} catch (error) {
console.error(error);
}
}
Simple example
Performing a POST request:
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
})
.then(function () {
// always executed
});
Performing multiple concurrent requests:
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
Promise.all([getUserAccount(), getUserPermissions()])
.then(function (results) {
const acct = results[0];
const perm = results[1];
});
Interceptors 를 Skip 하고싶을 경우
axios.interceptors.response.use(undefined, err => {
if (err.status === 401 && err.config && !err.config.__isRetryRequest) {
refreshLogin(getRefreshToken(),
success => {
setTokens(success.access_token, success.refresh_token)
err.config.__isRetryRequest = true
err.config.headers.Authorization = 'Bearer ' + getAccessToken()
axios(err.config)
},
error => { console.log('Refresh login error: ', error) }
)
}
})
개인적으론, err.config
에 새로운 Property 를 추가하기 보단, error.config.headers
에 추가하면 타입 심볼이 부서지지 않으므로 좀 더 선호한다. (서버에 해당 헤더를 보내지 않으려면 방법이 없긴 하지만...)
아니면, 동일한 axios.create()
를 사용하여 새로운 인스턴스를 만들자. (이러면 테스트할 때, axios-mock-adapter같은 mocking 객체에 인스턴스를 전달해야 정상적인 테스트가 가능한데,,, 이것도 영~;;;)
Form 전송 (application/x-www-form-urlencoded
)
기본적으로 axios는 JavaScript 객체를 'JSON'으로 직렬화(serialize) 합니다. application/x-www-form-urlencoded
포멧 대신 데이터를 보내려면 다음 옵션 중 하나를 사용할 수 있습니다.
브라우저
브라우저에서 다음과 같이 URLSearchParams API를 사용할 수 있습니다.
const params = new URLSearchParams();
params.append('param1', 'value1');
params.append('param2', 'value2');
axios.post('/foo', params);
NOTE |
URLSearchParams는 모든 브라우저에서 지원되지는 않지만, 사용할 수 있는 polyfill (url-search-params)이 있습니다. |
또는 qs 라이브러리를 사용하여 데이터를 인코딩 할 수 있습니다.
ES6+ 사용하는 경우는 아래와 같이 작성할 수 있습니다.
import qs from 'qs';
const data = { 'bar': 123 };
const options = {
method: 'POST',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
data: qs.stringify(data),
url,
};
axios(options);
Node.js
다음과 같이 querystring 모듈을 사용할 수 있습니다.
const querystring = require('querystring');
axios.post('http://something.com/', querystring.stringify({ foo: 'bar' }));
물론 qs 라이브러리를 사용할 수도 있습니다.
NOTE |
Node.js의 querystring 메소드는 중첩된 객체를 문자열화 하는데 문제점이 있습니다. 중첩된 객체를 문자열화 해야할 경우가 잦을 경우 qs 라이브러리 사용이 권장됩니다. |
Parameter Serializer
qs 모듈을 사용하면 편하다.
import axios from 'axios';
import qs from 'qs';
axios.defaults.baseURL = process.env.REACT_APP_BASE_URL || window.location.origin;
axios.defaults.headers.post['Accept'] = 'application/json';
axios.defaults.paramsSerializer = params => {
return qs.stringify(params)
};
Axios로 JWT Refresh 토큰 갱신
let isTokenRefreshing = false;
let refreshSubscribers = [];
const onTokenRefreshed = (accessToken) => {
refreshSubscribers.map((callback) => callback(accessToken));
};
const addRefreshSubscriber = (callback) => {
refreshSubscribers.push(callback);
};
axios.interceptors.response.use(
(response) => {
return response;
},
async (error) => {
const {
config,
response: { status },
} = error;
const originalRequest = config;
if (status === 401) {
if (!isTokenRefreshing) {
// isTokenRefreshing이 false인 경우에만 token refresh 요청
isTokenRefreshing = true;
const refreshToken = await AsyncStorage.getItem("refreshToken");
const { data } = await axios.post(
`http://localhost:3000/refresh/token`, // token refresh api
{
refreshToken,
}
);
// 새로운 토큰 저장
const {
accessToken: newAccessToken,
refreshToken: newRefreshToken,
} = data;
await AsyncStorage.multiSet([
["accessToken", newAccessToken],
["refreshToken", newRefreshToken],
]);
isTokenRefreshing = false;
axios.defaults.headers.common.Authorization = `Bearer ${newAccessToken}`;
// 새로운 토큰으로 지연되었던 요청 진행
onTokenRefreshed(newAccessToken);
}
// token이 재발급 되는 동안의 요청은 refreshSubscribers에 저장
const retryOriginalRequest = new Promise((resolve) => {
addRefreshSubscriber((accessToken) => {
originalRequest.headers.Authorization = "Bearer " + accessToken;
resolve(axios(originalRequest));
});
});
return retryOriginalRequest;
}
return Promise.reject(error);
}
);
See also
Favorite site
- Github - axios project site
- [추천] Axios 러닝 가이드
- 초보자를 위한 Axios vs Fetch
- Promise 기반의 HTTP Client 인 두 API를 비교
- 문법 비교 부터 JSONPlaceholder API를 호출했을 때의 차이점을 보여주며 설명
- 에러처리/타임아웃/취소
References
-
Maruzzings_devlog_-_axios_interceptors_token_refresh.pdf ↩