- 다양한 http 라이브러리
Node.Js 프로젝트를 진행하다보면 다른 서버와의 http 통신이 필요한 상황은 거의 무조건 오는데,
이때 사용 가능한 라이브러리는 axios, got, bent, node-fetch-npm 등 여러가지가 있습니다.
일전에 저도 이 다양한 라이브러리 중 어느것을 사용하는게 좋을지 확인하기 위해 비교 테스트를 진행해 포스팅한 적이 있습니다 (링크)
아무래도 가장 널리 쓰이던 라이브러리는 request 가 아니었을까 생각합니다. 해당 라이브러리에 베이스를 둔 request-promise 또한 많이 쓰였습니다. 하지만 작년 2월 request 라이브러리는 완전히 deprecated 되었고, 사내에서 관리중인 프로젝트에서도 조금씩 라이브러리 교체 작업을 진행해왔습니다.
여러 라이브러리를 비교 후 결국 production 레벨에서 선택한건 axios 입니다. 다른 라이브러리들은 너무 무겁거나, 과도하게 기능이 많거나, 너무 기능이 부족했습니다. (axios 도 나름 오래된 라이브러리고 많이 사용되는데, 왜 아직 메인 버전이 0.x 인지는 의문입니다..)
주로 request, request-promise 를 axios 로 변경하는 작업을 진행하며, axios config 에도 다양한 옵션이 있다는 점을 알게 되었습니다. 따라서 이번엔 해당 옵션들에 대해 어떤 기능을 하는지 정리하는 포스팅을 해 볼 생각입니다.
- axios configs
axios({
url: 'http://localhost:4000/users',
});
• url : 요청에 사용될 서버 URL 입니다.
axios({
method: 'get',
});
• method : 요청에 사용될 메소드이며, default 값은 get 입니다. 대문자도 가능합니다.
axios({
url: '/users',
baseURL: 'http://localhost:4000/',
});
• baseURL : url 값이 절대 URL 이 아니라면, 그 앞에 설정한 baseURL 이 붙습니다. 로컬에서 개발시엔 별 문제 없지만, production 레벨에선 이 값을 설정하는게 좀 더 편할 수 있습니다.
axios({
data: { id: 1 },
transformRequest: [function(data, headers) {
const payload = { ...data, key: 'some-key' };
return qs.stringify(payload);
}],
});
• transformRequest : 이 기능은 언제 쓸까 싶긴 하지만, 서버에 요청을 보내기 전에 데이터를 변환할 수 있습니다. 배열의 형태로 여러 변환 함수를 넣을 수 있으며, 배열의 마지막 함수는 버퍼의 문자열이나 인스턴스를 반환해야 합니다. (이 기능은 post, put, patch 메소드에만 적용 가능합니다)
위처럼 { id: 1 } 데이터에 key: 'some-key' 라는 값을 추가해 요청을 보낼 수 있습니다.
axios({
transformResponse: [function(data) {
const tmpData = JSON.parse(data);
return tmpData.data.map((item, i) => {
item.index = 1;
return item;
});
}],
}).then(result => {
console.info(result.data); // [ { id: 1, index: 0 }, { id: 2, index: 1 } ]
});
• transformResponse : 이 기능 또한 쓸 일이 있나 싶지만, 서버에서 받은 데이터를 변경해서 then/catch 로 전달합니다.
위처럼 원래 [{ id: 1 }, { id: 2 }] 로 응답받은 데이터를 transformResponse 를 사용해 index 를 추가하여 전달한 예시입니다.
axios({
headers: { 'X-Access-Token': 'access-token', 'Accept-Encoding': 'gzip' },
});
• headers : 서버에 전송될 사용자 정의 헤더입니다. gzip 압축을 허용한다는 Accept-Encoding 이나 커스텀 헤더를 보낼 수 있습니다.
axios({
url: 'http://localhost:4000/',
params: { key: 3 },
});
• params : 요청 URL 과 같이 전송될 매개 변수입니다. 위처럼 보낼 경우, http://localhost:4000?key=3 이렇게 요청을 보낸 것과 동일합니다.
axios({
params: { key: [1, 2, 3] },
paramsSerializer: paramObj => {
const params = new URLSearchParams();
for (const key in paramObj) {
params.append(key, paramObj[key])
}
return params.toString();
},
});
• paramsSerializer : 위에서 보낸 params 를 직렬화하는 옵션 함수입니다. 만약 params 에 배열을 전송한다면, 요청을 받는 서버 쪽에선 { 'key[]': [ '1', '2', '3' ] } 의 형태로 받아 'key[]' 를 파싱해야 합니다. 하지만 위처럼 직렬화 함수 설정을 통해 처리한다면 요청을 받는 서버쪽에선 { key: '1,2,3' } 의 형태로 params 데이터를 받을 수 있습니다.
axios({
data: { id: 3 },
});
• data : request body 로 전송할 데이터입니다. put, post, patch 메소드에만 적용 가능합니다.
axios({
timeout: 1000,
});
• timeout : 요청이 타임아웃되는 ms 를 지정합니다. 기본값은 0 으로 타임아웃이 적용되지 않습니다.
요청이 해당 설정 시간보다 지연될 경우 요청은 중단되며, catch 로 에러가 전달됩니다.
axios({
withCredentials: false,
});
• withCredentials : cross-site Access-Control 요청이 필요한 경우 해당 값을 true 로 설정하여 사용합니다.
사용 예시로는 서버와 클라이언트의 도메인이 서로 다르면 쿠키 전송이 되지 않는데, 이런 경우 사용할 수 있습니다.
const httpAdapter = require('axios/lib/adapters/http');
const settle = require('axios/lib/core/settle');
axios({
url: 'http://localhost:4000/',
adapter: config => {
return new Promise((resolve, reject) => {
httpAdapter(config).then(response => {
if (response.status === 200) {
response.status = 503;
}
settle(resolve, reject, response);
}).catch(reject);
});
},
}).catch(err => {
console.error(err); // Error: Request failed with status code 503 ...
});
• adapter : 별도의 커스텀 adapter 를 추가해서 요청에 대해 커스텀 핸들링한 응답을 받을 수 있습니다.
위 예시에선 response status 가 200 일 경우 503 으로 세팅해 응답하도록 adapter 를 추가했고, 그 결과 정상적으로 왔을 응답이 503 에러로 처리되어 catch 에서 찍히는것을 확인할 수 있습니다. (adapter 는 Promise 를 반환해야 합니다)
axios({
auth: {
username: 'xxx',
password: 'xxxx',
},
});
• auth : HTTP 기본 인증이 사용되며 credentials 를 제공함을 나타냅니다. 기존의 Authorization 헤더를 덮어쓰는 헤더 설정이 들어가게 됩니다. auth 를 설정하지 않았을 경우와 비교했을 때, 요청 받은 서버쪽에서 그 차이를 아래와 같이 확인할 수 있습니다.
axios({
responseType: 'json',
});
• responseType : ['arraybuffer', 'blob', 'document', 'json', 'text', 'stream'] 이 값들 중 서버에서 응답할 데이터 타입을 설정할 수 있습니다. 디폴트는 'json' 입니다.
axios({
responseEncoding: 'utf8',
});
• responseEncoding : 응답 디코딩에 사용할 인코딩을 나타내며, 'utf8' 이 디폴트입니다. responseType 이 stream 인 경우엔 해당 설정을 무시합니다.
axios({
xsrfCookieName: 'XSRF-TOKEN',
});
• xsrfCookieName : xsrf 토큰 값으로 사용할 쿠키 이름입니다.
axios({
xsrfHeaderName: 'X-XSRF-TOKEN',
});
• xsrfHeaderName : xsrf 토큰값을 운반하는 HTTP 헤더 이름입니다.
# 위에서 나오는 xsrf 는 csrf (Cross Site Request Forgery) 라고도 하며 사용자의 의도와 관계없이 행해지는 공격 기법인데, 예를 들어 공격자가 심어놓은 스크립트에 의한 것이 있을 수 있고 이를 방어하기 위해 csrf(xsrf) token 이 사용됩니다.
axios({
onUploadProgress: progressEvent => {
...
},
onDownloadProgress: progressEvent => {
...
},
});
• onUploadProgress : 업로드 프로그레스 이벤트를 처리합니다.
• onDownloadProgress : 다운로드 프로그레스 이벤트를 처리합니다.
위 두 옵션은 브라우저에서만 사용되는 옵션이므로 더 파보진 않겠습니다. native progressEvent 를 받아 ui 상에서 처리할 수 있는 코드 추가가 가능한 것으로 보입니다.
axios({
url: 'http://localhost:4000/',
maxContentLength: 1,
}).catch(err => {
console.error(err); // Error: maxContentLength size of 1 exceeded
});
• maxContentLength : 응답 컨텐츠의 최대 크기를 설정하며, 단위는 Bytes 입니다.
위 예시처럼 maxContentLength 값을 설정하고 요청을 보낼 경우 응답 컨텐츠의 사이즈가 설정값을 넘어 catch 에서 처리되는 것을 확인할 수 있습니다.
axios({
maxBodyLength: 2000,
});
• maxBodyLength : http 요청 컨텐츠의 최대 크기를 설정하며, 단위는 Bytes 입니다.
이 옵션은 Node.Js 에서만 사용할 수 있습니다.
axios({
validateStatus: status => {
// return status >= 200 && status < 300; - default
return status !== 200;
},
});
• validateStatus : 응답 상태 코드에 대해 true | false 로 promise 를 resolve 하거나 reject 합니다.
기본값으로 axios 는 2xx 대의 응답 코드에 대해선 promise 를 resolve 합니다. 하지만 응답코드 200 외에는 전부 에러로 처리하고 싶다면 위처럼 커스텀 validateStatus 함수를 작성할 수 있습니다.
axios({
maxRedirect: 5,
});
• maxRedirect : Node.Js 에서 리다이렉션이 가능한 최대 갯수를 정의하며, 0 으로 설정하면 리다이렉션이 되지 않습니다.
axios({
socketPath: null,
});
• socketPath : Node.Js 에서 사용될 UNIX 소켓을 정의합니다. null 이 기본값이며, 예를 들어 '/var/run/docker.sock' 로 설정하면 docker daemon 으로 요청을 보냅니다.
axios({
proxy: {
host: '127.0.0.1',
port: 9000,
auth: {
username: 'xxx',
password: 'xxxx',
},
},
});
• proxy : 프록시 서버를 설정하는 옵션입니다. 옵션 혹은 환경 변수를 무시하고 프록시를 사용하지 않으려면 false 로 설정합니다.
axios 옵션에선 socketPath, proxy 둘 중 하나만 사용할 수 있습니다. 만약 둘 다 지정되면, socketPath 가 사용됩니다.
axios({
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),
});
• httpAgent, httpsAgent : Node.Js 에서 http, https 요청을 보낼 때 사용할 커스텀 에이전트를 정의할 수 있습니다.
기본적으로 Node.Js 의 http, https 에이전트는 모든 새 요청에 대해 새로운 tcp 연결을 생성합니다. 이러한 새 연결 설정 비용이 들지 않게 하기 위해 { keepAlive: true } 와 같은 옵션으로 기존 연결을 재사용하게끔 설정할 수 있습니다.
const axios = require('axios');
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios({
url: 'http://localhost:4000/',
cancelToken: source.token,
}).catch(err => {
console.error(err); // Cancel { message: 'Want to cancel' }
console.info(axios.isCancel(err)); // true
});
source.cancel('Want to cancel');
• cancelToken : axios 의 CancelToken 을 사용해 요청을 취소할 수 있습니다. (자세한 내용 링크)
위 예시처럼 cancelToken 을 넣어 보내면, 요청이 취소되어 reject 로 처리되고 그 에러가 cancel 된 요청인지도 확인할 수 있습니다.
위 코드에서 마지막 라인을 제거하면, 요청은 cancelToken 이 있더라도 취소되지 않습니다.
axios({
decompress: true,
});
• decompress : 응답 바디를 자동으로 압축을 풀 것인지를 나타내는 옵션입니다. 기본값은 true 입니다.
이 옵션은 Node.Js 에서만 사용 가능합니다.
대부분 몰랐던 옵션들이고, 대체로 사용할 것 같진 않지만 몇몇 유용해 보이는 옵션도 있었습니다.
여기까지 axios configs 에 대한 정리를 마치도록 하겠습니다. (참고 링크)
'Backend > Node.js' 카테고리의 다른 글
SharedArrayBuffer & Atomics (SharedMemory) (0) | 2022.04.03 |
---|---|
package-lock.json 이란? (0) | 2022.01.22 |
[Node.js] Date 라이브러리 퍼포먼스 비교 (1) | 2021.03.06 |
[Node.js] Date 라이브러리 비교 (0) | 2021.02.27 |
[Node.js] Http 라이브러리 비교 (3) | 2020.06.08 |