서버와 통신하는 라이브러리 3대장으로 AJAX
,FETCH
,AXIOS
가 있지만,
현업에선 AXIOS
를 압도적으로 많이쓴다. 왜 그런지 부터 알고가자.
AJAX
는 Jquery
기반이기 때문에 jquery
를 사용해야 호완성이 보장되고 Promise
기반이 아닌 callback
기반이기 때문에 Promise
기반을 주로 쓰는 요즘 추세와 맞지않는다.
Fetch
는 js가 ES6버전으로 업글되면서 들어온 내장 라이브러리인데 지원하지않는 브라우저가 존재하고 네트워크 에러발생시 response timeout기능이 없어 따로 만들어주거나 하염없이 기다려야한다.
또한 json으로 데이터를 직렬화해주는 과정이 필요하기 때문에 주류로 쓰기엔 불편한점이 많다.
axios
는 위에 설명한 애들이 가지지 못한 장점과 더불어 확장된 기능 또한 사용이 가능하기때문에 현업에선 axios
를 주류로 많이 쓰는 추세이다. 유일한 단점은 외부 라이브러리라 설치해야된다는 점 뿐인거같다.
모든 과정은 Axios 공식 사이트를 기반으로 설명하겠다.
또한 axios는 프론트단에서 주로 사용하기에 React + js기반으로 설명하겠다.
$ npm install axios
$ yarn add axios
import axios from "axios"
const restApi = axios.default;
//GET QUERY 요청
restApi.get('/user?ID=1234')
.then((response)=>{
//성공 핸들링
console.log(reponse);
})
.catch((error)=>{
//에러 핸들링
console.log(error);
})
.then(()=>{
//항상 실행되는 영역 (final)
});
//GET PARAMS 요청
restApi.get('/user',{
params:{
ID:1234
}
})
.then((response)=>{
//성공 핸들링
console.log(reponse);
})
.catch((error)=>{
//에러 핸들링
console.log(error);
})
.then(()=>{
//항상 실행되는 영역 (final)
});
//여러개의 요청 처리 ( restApi.spread()도 존재한다. )
restApi.all([restApi.get('/userID=1234'),
restApi.get('/user/12345/permissions')])
.then((results)=>{
//성공 핸들링
const acct = results[0];
const perm = results[1];
})
.catch((errors)=>{
//에러 핸들링
const acctError = errors[0];
const permError = errors[1];
});
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
//성공 핸들링
console.log(response);
})
.catch(function (error) {
//에러 핸들링
console.log(error);
});
put
, patch
, delete
는 post의 확장문이기 때문에 따로 설명하진 않겠다.
(axios에 내장함수로 있다.)
import axios from "axios";
axios.create({
// `url`은 요청에 사용될 서버 URL입니다.
url: "/user",
// `method`는 요청을 생성할때 사용되는 메소드입니다.
method: "get", // 기본값
// `url`이 절대값이 아닌 경우 `baseURL`은 URL 앞에 붙습니다.
// 상대적인 URL을 인스턴스 메서드에 전달하려면 `baseURL`을 설정하는 것은 편리합니다.
baseURL: "https://some-domain.com/api",
// `transformRequest`는 요청 데이터를 서버로 전송하기 전에 변경할 수 있게 해줍니다.
// 이것은 'PUT', 'POST', 'PATCH', 'DELETE' 메소드에서만 적용됩니다.
// 마지막 함수는 Buffer, ArrayBuffer, FormData 또는 Stream의 인스턴스 또는 문자열을 반환해야 합니다.
// 헤더 객체를 수정할 수 있습니다.
transformRequest: [
function (data, headers) {
// 데이터를 변환하려는 작업 수행
return data;
},
],
// `transformResponse`는 응답 데이터가 then/catch로 전달되기 전에 변경할 수 있게 해줍니다.
transformResponse: [
function (data) {
// 데이터를 변환하려는 작업 수행
return data;
},
],
// `headers`는 사용자 지정 헤더입니다.
headers: { "X-Requested-With": "XMLHttpRequest" },
// `params`은 요청과 함께 전송되는 URL 파라미터입니다.
// 반드시 일반 객체나 URLSearchParams 객체여야 합니다.
// 참고: null이나 undefined는 URL에 렌더링되지 않습니다.
params: {
ID: 12345,
},
// `paramsSerializer`는 `params`의 시리얼라이즈를 담당하는 옵션 함수입니다.
// (예: https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
paramsSerializer: function (params) {
return Qs.stringify(params, { arrayFormat: "brackets" });
},
// `data`는 요청 바디로 전송될 데이터입니다.
// 'PUT', 'POST', 'PATCH', 'DELETE' 메소드에서만 적용 가능합니다.
// `transformRequest`가 설정되지 않은 경우 다음 타입 중 하나여야 합니다.
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - 브라우저 전용: FormData, File, Blob
// - Node 전용: Stream, Buffer
data: {
firstName: "Fred",
},
// 바디로 전송하는 데이터의 대안 문법
// POST 메소드
// 키가 아닌 값만 전송됩니다.
data: "Country=Brasil&City=Belo Horizonte",
// `timeout`은 요청이 시간 초과되기 전의 시간(밀리초)을 지정합니다.
// 요청이 `timeout`보다 오래 걸리면 요청이 중단됩니다.
timeout: 1000, // 기본값은 `0` (타임아웃 없음)
// `withCredentials`은 자격 증명을 사용하여 사이트 간 액세스 제어 요청을 해야 하는지 여부를 나타냅니다.
withCredentials: false, // 기본값
// `adapter`'은 커스텀 핸들링 요청을 처리할 수 있어 테스트가 쉬워집니다.
// 유효한 Promise 응답을 반환해야 합니다. (lib/adapters/README.md 참고)
adapter: function (config) {
/* ... */
},
// `auth`는 HTTP Basic 인증이 사용되며, 자격 증명을 제공합니다.
// `auth`를 사용하면, `Authorization` 헤더가 설정되어 `headers`를 사용하여 설정한 기존의 `Authorization` 사용자 지정 헤더를 덮어씁니다.
// 이 파라미터를 통해 HTTP Basic 인증만 구성할 수 있음을 참고하세요.
// Bearer 토큰 등의 경우 `Authorization` 사용자 지정 헤더를 대신 사용합니다.
auth: {
username: "janedoe",
password: "s00pers3cret",
},
// `responseType`은 서버에서 받는 데이터의 타입입니다.
// 옵션: 'arraybuffer', 'document', 'json', 'text', 'stream'
// 브라우저 전용: 'blob'
responseType: "json", // 기본값
// `responseEncoding`은 응답 디코딩에 사용할 인코딩입니다.
// Node.js 전용
// 참고: 클라이언트 사이드 요청 또는 `responseType`이 'stream'이면 무시합니다.
responseEncoding: "utf8", // 기본값
// `xsrfCookieName`은 xsrf 토큰 값으로 사용할 쿠키의 이름입니다.
xsrfCookieName: "XSRF-TOKEN", // 기본값
// `xsrfHeaderName`은 xsrf 토큰 값을 운반하는 HTTP 헤더의 이름입니다.
xsrfHeaderName: "X-XSRF-TOKEN", // 기본값
// `onUploadProgress`는 업로드 진행 이벤트를 처리합니다.
// 브라우저 전용
onUploadProgress: function (progressEvent) {
// 업로드 진행 이벤트 작업 수행
},
// `onDownloadProgress`는 다운로드로드 진행 이벤트를 처리합니다.
// 브라우저 전용
onDownloadProgress: function (progressEvent) {
// 다운로드 진행 이벤트 작업 수행
},
// `maxContentLength`는 node.js에서 허용되는 http 응답 콘텐츠의 최대 크기를 바이트 단위로 정의합니다.
maxContentLength: 2000,
// `maxBodyLength`는 허용되는 http 요청 콘텐츠의 최대 크기를 바이트 단위로 정의합니다.
// Node.js 전용
maxBodyLength: 2000,
// `validateStatus`는 지정된 HTTP 응답 상태 코드에 대한 Promise를 이행할지 또는 거부할지 여부를 정의합니다.
// 만약 `validateStatus`가 true를 반환하면(또는 'null' 또는 'undefined'으로 설정) Promise는 이행됩니다.
// 그렇지 않으면, 그 Promise는 거부될 것이다.
validateStatus: function (status) {
return status >= 200 && status < 300; // 기본값
},
// `maxRedirects`는 node.js에서 리디렉션 최대값을 정의합니다.
// 0으로 설정하면 리디렉션되지 않습니다.
maxRedirects: 5, // 기본값
// `socketPath`는 node.js에서 사용될 UNIX 소켓을 정의합니다.
// 예: '/var/run/docker.sock' 도커 데몬에 요청을 보냅니다.
// 오직 `socketPath` 또는 `proxy`만 지정할 수 있습니다.
// 둘 다 지정되면 `socketPath`가 사용됩니다.
socketPath: null, // 기본값
// `httpAgent`와 `httpsAgent`는 각각 node.js에서 http 및 https 요청을 수행할 때 사용할 사용자 지정 에이전트를 정의합니다.
// 이렇게 하면 기본적으로 활성화되지 않은 `keepAlive`와 같은 옵션을 추가할 수 있습니다.
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),
// `proxy`는 프록시 서버의 호스트이름, 포트, 프로토콜을 정의합니다.
// 기존의 `http_proxy`와 `https_proxy` 환경 변수를 사용하여
// 프록시를 정의할 수도 있습니다.
// 프록시 구성에 환경 변수를 사용하는 경우, 'no_proxy' 환경 변수를
// 쉼표로 구분된 프록시가 되지 않는 도메인 목록으로 정의할 수도 있습니다.
// `false`를 사용하면 프록시를 사용하지 않고, 환경 변수를 무시합니다.
// `auth`는 프록시에 연결하는데 HTTP Basic auth를 사용해야 함을 나타내며,
// 자격 증명을 제공합니다. 그러면 `Proxy-Authorization` 헤더가 설정되고,
// `headers`를 사용하여 기존의 `Proxy-Authorization` 사용자 지정 해더를 덮어씁니다.
// 만약 프록시 서버가 HTTPS를 사용한다면, 프로토콜을 반드시 `https`로 설정해야 합니다.
proxy: {
protocol: "https",
host: "127.0.0.1",
port: 9000,
auth: {
username: "mikeymike",
password: "rapunz3l",
},
},
// `cancelToken`은 요청을 취소하는 데 사용할 수 있는 취소 토큰을 지정합니다.
// (자세한 내용은 요청 취소 섹션 참조)
cancelToken: new CancelToken(function (cancel) {}),
// `decompress`는 응답 바디의 자동 압축 해제 여부를 나타냅니다.
// `true`로 설정하면, 압축 해제된 모든 응답에서 'content-encoding' 헤더도 제거됩니다.
// Node.js 전용 (XHR은 압축 해제할 수 없습니다)
decompress: true, // 기본값
});
많은 설정이 있는데 꼭 알아야 하는 것만 설명하겠다.
url
: 말그대로 통신 할 url을 뜻한다. (config에 이걸 미리 설정하는일은 극히 드물다)
baseUrl
: 기본이되는 url을 뜻한다. 설정하면 baseUrl
+ url
형태로 스트링이 join
된다.
주로 api 서버 주소를 설정할때 쓴다.
transformRequest
: 요청을 보내기 직전 실행 할 기능을 뜻한다. (interceptor)
transformResponse
: 응답을 받기 직전 실행 할 기능을 뜻한다. (interceptor)
headers
: 사용자 지정헤더이다. 기본 헤더 스키마에 추가된다고 생각하면된다.
params
: get요청중 params데이터가 필요할때 사용한다.
paramsSerializer
: params 데이터를 서버쪽 dto validate에 맞게 직렬화 할때 사용한다.
(params 전용 interceptor라고 봐도 무방하다.)
data
: 요청시 body 데이터이다. post요청 및 post확장 요청인 patch, delete, put에 주로쓰인다.
timeout
: 서버와 통신시 최대 응답 대기 시간이다. 단위는 ms이다. 1000 = 1초
최대 응답 대기 시간이 넘어가면 axios는 error를 반환한다.
withCredentials
: cors정책과 연관된 설정이다.
간단히 말하면 back serv가 front serv에 있는 쿠키값을 공유하고 싶다면 true, 아닐경우 false를 하면된다. 쿠키는 Request headers안 Cookies에 존재한다.
auth
: 서버와 권한을 통신할때 주로 쓰인다. 설정시 headers에 Authorization의 값이 된다.
이곳에 토큰을 담아도되고 로그인 정보를 담는 식으로 많이 쓴다.
responseType
: 서버에서 받는 데이터의 타입이다.
onUploadProgress
: 서버에 업로드 할 때 실행되는 이벤트이다.
주로 업로드 progress bar를 만들때 많이 사용한다.
onDownloadProgress
: 서버에서 다운로드 받을때 실행되는 이벤트이다.
주로 다운로드 progress bar를 만들때 많이 사용한다.
나머지는 딥한 내용이라 넘어가겠다
{
// `data`는 서버가 제공하는 응답입니다.
data: {},
// `status`는 HTTP 상태 코드입니다.
status: 200,
// `statusText`는 HTTP 상태 메시지입니다.
statusText: 'OK',
// `headers`는 HTTP 헤더입니다.
// 모든 헤더 이름은 소문자이며, 괄호 표기법을 사용하여 접근할 수 있습니다.
// 예시: `response.headers['content-type']`
headers: {},
// `config`는 요청을 위해 `Axios`가 제공하는 구성입니다.
config: {},
// `request`는 이번 응답으로 생성된 요청입니다.
// 이것은 node.js에서 마지막 ClientRequest 인스턴스 입니다.
// 브라우저에서는 XMLHttpRequest입니다.
request: {}
}
이 중 중요한건 status
라고 필자는 생각한다.
응답코드만 잘 알고있어도 서버 잘못인지 프론트 잘못인지 어디서 버그가 생겼는지 파악하기 쉽다.
다 외울 필요는 없고 앞자리가 의미하는 바와 500,404,200,403 정도만 확실히 기억해두면 좋다.
then
또는 catch
로 처리되기 전에 요청과 응답을 가로챌수 있는 기능이다.
// 요청 인터셉터 추가하기
axios.interceptors.request.use(function (config) {
// 요청이 전달되기 전에 작업 수행
return config;
}, function (error) {
// 요청 오류가 있는 작업 수행
return Promise.reject(error);
});
// 응답 인터셉터 추가하기
axios.interceptors.response.use(function (response) {
// 2xx 범위에 있는 상태 코드는 이 함수를 트리거 합니다.
// 응답 데이터가 있는 작업 수행
return response;
}, function (error) {
// 2xx 외의 범위에 있는 상태 코드는 이 함수를 트리거 합니다.
// 응답 오류가 있는 작업 수행
return Promise.reject(error);
});
const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
axios.get('/user/12345')
.catch(function (error) {
if (error.response) {
// 요청이 전송되었고, 서버는 2xx 외의 상태 코드로 응답했습니다.
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
// 요청이 전송되었지만, 응답이 수신되지 않았습니다.
console.log(error.request);
} else {
// 오류가 발생한 요청을 설정하는 동안 문제가 발생했습니다.
console.log('Error', error.message);
}
console.log(error.config);
});
validateStatus
config 옵션을 사용하면, 특정 코드에 대한 반환을 재정의 할 수있다.
axios.get('/user/12345', {
validateStatus: function (status) {
return status < 500; // 상태 코드가 500 미만인 경우 resolve됌
//(상태코드 500미만은 error로 처리하지않음)
}
})
toJSON
을 사용하면, HTTP 에러에 대한 더 많은 정보를 객체 형식으로 가져온다.
axios.get('/user/12345')
.catch(function (error) {
console.log(error.toJSON());
});
import qs from 'qs';
const data = { 'bar': 123 };
const options = {
method: 'POST',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
data: qs.stringify(data),
'https://example.com',
};
axios(options);
//요청 data : https://example.com?bar=123
const form = new FormData();
form.append('my_field', 'my value');
form.append('my_buffer', new Buffer(10));
form.append('my_file', files[0]);
axios.post('https://example.com', form, { headers: {"Content-Type": "multipart/form-data"} })