axios, 단순 요청도구가 아니었다.

Hushed_Mind·2025년 4월 27일
post-thumbnail

솔직히 말하면, 나도 처음엔 axios를 단순히 "fetch보다 쓰기 편한 애"정도로만 생각했다.
실제로도 그런 설명을 많이 봐왔다.
하지만 프로젝트를 하면스 API 연동이 점점 많아지고, 에러도 자 주 터지다 보니 문득 이런 생각이 들었다.

"axios가 진짜로 뭘 해주는거지? fetch랑 뭐가 다르고, 내부에서 뭘 조작하고 있는 걸까?"

그래서 하나하나 천천히 파보기로 했다.


왜 axios를 쓰는 걸까?

fetch도 요청은 보낼 수 있다.
하지만 코드를 짜다 보면 이런 반복이 너무 많다.

fetch('/api/user', {
	method: "POST",
  	headers: {
    	'Content-Type': 'application/json'
    },
  	body: JSON.stringify({name:'홍길동'})
})
.then((res) => {
	if (!res.ok) throw new Error("에러");
  	return res.json();
})
  • JSON.stringify
  • res.ok 체크
  • 응답 파싱

결국 axios는 이런 걸 대신 해주는 거다.
그런데 여기서 멈추면 진짜 아쉬운게, axios는 단순히 문법 편하게 만드는 도우미가 아니다.
axios는 HTTP 요청을 구조적으로 추상화해서, 우리가 통신 흐름을 통제할 수 있게 해주는 도구다.


요청은 단순하지 않다

HTTP 요청은 단순히 URL + 데이터만 보내는 게 아니다.
요청을 보내기 위해선 반드시 본문(body)의 구조와 그 구조를 설명해줄 헤더(header)가 필요하다.
예를 들어 이런 상황을 상상해보자.

"서버야, 내가 데이터를 보낼 건데 JSON 형식이야! 그러니까 JSON으로 파싱해서 읽어줘!"
이걸 말해주는게 바로 Content-Type이다.

Content-Type: application/json

만약 이걸 잘못 보내면 서버는 본문을 제대로 해석하지 못한다.
즉, 우리가 아무리 body를 잘 만들어도, Content-Tytpe이 엉뚱하면 서버는 "이거 뭐지?"하고 에러를 낸다.


axios는 이걸 자동으로 해준다.

axios.post('/api/user', {name: '홍길동'});

위 코드는 다음과 같이 작동한다

  • 내부에서 JSON.stringify() 처리
  • 자동으로 Content-Type: application/json 붙임
  • 응답 JSON 자동 파싱
  • 에러 status code에 따라 catch로 보내줌

내가 신경 써야 할 건 오로지 데이터뿐이다.
그게 axios의 핵심 강점 중 하나다.


그런데 문제는... Content-Type은 상황에 따라 바뀐다.

예 1: x-www-form-urlencoded

HTML <form>에서 데이터를 보낼 때는 보통 이렇게 생긴다

name=홍길동&age=24

이런 방식은 application/x-www-form-urlencoded라는 형식인데, JSON이 아니다.
이때는 직접 Content-Type을 바꿔줘야 한다.

import qs from 'qs';

axios.post('/api/user', qs.stringify({name:"홍길동"}), {
	headers: {
    	'Content-Type': 'application/x-www-form-urlencoded'
    }
});

그리고 body는 JSON이 아니라 쿼리스트링처럼 만들어야 한다.
(즉, stringify 방식도 바뀜)


예 2: 파일 업로드 - multipart/form-data

이미지나 파일을 업로드할 때는 완전히 다른 형식이 필요하다.

const formData = new FormData();
formData.append('file', file);

axios.post('/upload', formData);

여기서 주의할 점은,
multipart/form-databoundary라는 복잡한 값이 필요해서 Content-Type을 직접 쓰면 안 된다.

headers: {
	'Content-Type': 'multipart/form-data' // X
}

axios 가 내부에서 알아서 설정하게 두는 게 안전하다.


axios는 "단순한 요청 도우미"를 넘어서

내가 axios를 다시 보게 된 결정적 포인트는 인터셉터였다.

axios.interceptors.request.use((config) => {
  config.headers.Authorization = `Bearer ${token}`;
  return config;
});

요청을 보내기 전에 가로채서 헤더를 추가할 수 있고,
응답을 받은 후에도 가로채서 메시지를 조작하거나 에러 핸들링도 할 수 있다.
이걸 보고 딱 느꼈다.

"axios"는 단순히 "요청 한 번 보내자"가 아니라
요청의 전 과정을 내가 가공하고 제어할 수 있는 구조를 제공해주는 도구구나."


자주 겪은 헷갈리는 포인트들

  1. Content-Type이 json인데 body가 JSON이 아니면?
    -> 서버가 파싱 실패 (400 오류)
  2. application/json 쓰면 브라우저가 OPTIONS 요청을 보내는 경우도 있다.
    -> 이건 CORS 사전 요청. 서버에서 OPTIONS 허용해야 함.
  3. axios.post(url,string)을 썼는데 Content-Type을 안 바꾸면?
    -> axios는 기본적으로 application/json을 붙이니까, string body는 해석 오류 가능

정리하면..

  • axios는 단순 요청 도구가 아니라, HTTP 통신 흐름 전체를 관리할 수 있게 해주는 인터페이스다.
  • Content-Type은 본문의 구조를 서버에 알려주는 설명서고, 이게 맞지 않으면 서버는 말을 이해 못한다.
  • 상황에 따라 본문 인코딩과 Content-Type이 같이 움직이며, axios는 대부분 자동으로 처리하지만 가끔은 우리가 직접 설정해야 한다.

결론

지금까지는 그냥 "axios 쓰면 편하네~" 하고 썼다면,
앞으로는 이게 어떤 흐름으로 작동하고,
서버와 어떤 형식으로 대화하게 만드는지를 좀 더 구조적으로 이해하고 다뤄보자.

이해한 만큼 에러는 줄어들고,
이해한 만큼 디버깅은 빨라지고,
이해한 만큼 확장성과 통제가 가능해진다.

profile
개발 공부 블로그

0개의 댓글