티스토리 뷰
목차
개발자라면 한 번쯤 마주쳤을 얄미운 에러 메시지, "415 Unsupported Media Type". 분명 나는 제대로 보낸 것 같은데, 서버는 도무지 내 요청을 이해하지 못하겠다며 고개를 절레절레 흔드는 상황이죠. 마치 한국어를 못 알아듣는 외국인 점원에게 열심히 한국어로 주문하는 듯한 답답함! 이 글을 통해 더 이상 415 에러 앞에서 좌절하지 않고, 당당하게 문제를 해결하는 방법을 알아봅시다. 커피 한 잔 준비하시고, 차근차근 따라오세요!
❓ 415 Unsupported Media Type 에러, 너 정체가 뭐냐?
415 Unsupported Media Type 에러는 우리가 웹 서버에 무언가를 요청할 때, "이봐, 네가 보낸 데이터 형식은 내가 처리할 수 없는 거야!"라고 서버가 알려주는 HTTP 상태 코드입니다. 조금 더 풀어서 설명하자면, 클라이언트(우리 웹 브라우저나 앱)가 서버에게 데이터를 보낼 때, 그 데이터의 종류(미디어 타입, 예를 들어
application/json
이나
application/xml
같은)를 서버가 이해하거나 지원하지 않을 때 발생하는 문제입니다.
쉽게 비유하자면:
- 여러분이 레스토랑에 가서 스테이크를 주문하려고 하는데, 메뉴판에는 파스타 종류만 잔뜩 있고 스테이크는 취급하지 않는다고 상상해 보세요. 이때 웨이터가 "죄송하지만, 저희는 스테이크는 팔지 않습니다."라고 말하는 것과 비슷합니다. 여기서 여러분의 '스테이크 주문'이 '지원하지 않는 미디어 타입의 요청'이고, 웨이터의 답변이 '415 에러'인 셈이죠.
서버는 자신이 처리할 수 있는 데이터 형식(
Content-Type
)을 미리 정해두고 있는데, 클라이언트가 이 약속을 어기고 엉뚱한 형식으로 데이터를 보내면 "나 이거 몰라, 못 받아줘!" 하고 415 에러를 반환하는 것입니다.
🎯 내 잘못? 서버 잘못? 415 에러의 주범을 찾아라! (주요 원인)
415 에러는 생각보다 다양한 원인으로 발생할 수 있습니다. 마치 탐정이 된 것처럼, 주요 용의자들을 하나씩 살펴봅시다.
- 클라이언트의 소심한 침묵 또는 엉뚱한 고백 (잘못된
Content-Type헤더 설정)- 가장 흔한 원인! 클라이언트가 서버에 요청을 보낼 때, HTTP 요청 헤더에
Content-Type을 아예 명시하지 않거나, 서버가 지원하지 않는 엉뚱한 값으로 설정한 경우입니다. - 예시: 서버는 JSON 형식(
application/json)의 데이터만 받도록 설정되어 있는데, 클라이언트가 아무런 표시 없이 데이터를 보내거나,text/plain같은 다른 타입으로 보내는 경우. 서버는 "이게 대체 무슨 데이터야?" 하며 당황할 수밖에 없겠죠.
- 가장 흔한 원인! 클라이언트가 서버에 요청을 보낼 때, HTTP 요청 헤더에
- 서버의 편식 (서버에서 지원하지 않는 미디어 형식)
- 클라이언트가
Content-Type을 제대로 명시했더라도, 서버 자체가 해당 데이터 형식을 처리할 능력이 없는 경우입니다. - 예시: 이미지 파일을 업로드하려고 하는데, 서버가 해당 이미지 파일 형식(예:
.webp)을 처리하도록 구성되어 있지 않은 경우. 서버는 "나는.jpg나.png만 먹을 수 있는데, 이건 소화 못 해!"라고 외치는 것과 같습니다.
- 클라이언트가
- 번역의 오류 (인코딩 문제)
- 요청 본문(payload)이 서버가 예상하지 못한 방식으로 인코딩된 경우에도 발생할 수 있습니다. 대표적으로 문자 인코딩 방식(
charset)이 클라이언트와 서버 간에 일치하지 않을 때 문제가 생기곤 합니다. - 예시: 클라이언트는
UTF-8로 데이터를 보냈는데, 서버는EUC-KR로 해석하려고 하면 글자가 깨지거나 제대로 인식하지 못하며 415 에러를 띄울 수 있습니다.
- 요청 본문(payload)이 서버가 예상하지 못한 방식으로 인코딩된 경우에도 발생할 수 있습니다. 대표적으로 문자 인코딩 방식(
- Spring 개발자의 단골손님:
@RequestBody어노테이션과의 불협화음 (Java Spring 환경 등)- Java Spring 프레임워크를 사용한다면
@RequestBody어노테이션을 자주 접하게 됩니다. 이 어노테이션은 클라이언트가 전송하는 HTTP Body의 내용(주로 JSON이나 XML)을 Java 객체로 똑똑하게 변환해 주는 역할을 하죠. - 문제는, 클라이언트가 보낸 데이터의
Content-Type과 서버에서@RequestBody를 통해 기대하는 데이터 형식이 일치하지 않을 때 발생합니다. - 예시: 가장 흔한 실수는 HTML 폼 (
)을 통해 데이터를 전송할 때입니다. 폼 데이터의 기본Content-Type은application/x-www-form-urlencoded인데, 서버 컨트롤러 메소드의 파라미터가@RequestBody로 선언되어 JSON(application/json)을 기대하고 있다면? 바로 415 에러가 여러분을 맞이할 겁니다!
- Java Spring 프레임워크를 사용한다면
😫 415 에러, 방치하면 생기는 일 (에러의 영향)
"까짓것 에러 하나쯤이야" 하고 넘길 수 있을까요? 415 에러는 생각보다 큰 파장을 불러일으킬 수 있습니다.
- API 요청 실패 및 기능 마비: 가장 직접적인 영향입니다. 서버가 클라이언트의 요청을 처리하지 못하니, 우리가 만들고 있는 서비스의 핵심 기능이 동작하지 않게 됩니다. 회원가입, 글쓰기, 상품 주문 등 중요한 작업들이 모두 멈춰 설 수 있습니다.
- 사용자 경험 와르르: 정상적으로 작동해야 할 서비스가 먹통이 되면, 사용자들은 당연히 불편을 느끼고 실망하게 됩니다. 이는 곧 서비스 이탈로 이어질 수 있는 심각한 문제입니다.
- 개발자의 소중한 시간 증발: 원인을 알 수 없는 에러는 개발자를 괴롭힙니다. 415 에러 역시 원인을 정확히 파악하지 못하면 디버깅에 많은 시간을 쏟게 되고, 이는 곧 프로젝트 일정 지연으로 이어질 수 있습니다.
💡 개발자 구원 등판! 415 에러 해결 완벽 가이드
자, 이제 답답했던 415 에러와 작별할 시간입니다. 아래 해결 방법들을 통해 문제의 실마리를 찾아봅시다.
1. 클라이언트야, 정신 차리고
Content-Type
제대로 알려줘! (클라이언트 측)
가장 먼저 확인하고 수정해야 할 부분은 클라이언트가 서버로 요청을 보낼 때 HTTP 요청 헤더에 정확한
Content-Type
을 명시 하는 것입니다.
- JSON 데이터 전송 시:
Content-Type: application/json - XML 데이터 전송 시:
Content-Type: application/xml - 폼 데이터 전송 시 (파일 업로드 없을 때):
Content-Type: application/x-www-form-urlencoded - 폼 데이터 전송 시 (파일 업로드 포함 시):
Content-Type: multipart/form-data
JavaScript (AJAX, Fetch API 등) 사용 시
Content-Type
설정 예시:
// 예시: jQuery AJAX 사용 시
$.ajax({
type: 'POST',
url: '/api/resource',
data: JSON.stringify(jsonData), // 데이터를 반드시 JSON 문자열로 변환!
contentType: 'application/json; charset=utf-8', // Content-Type 명시! (UTF-8 인코딩 사용 예시)
success: function(response) {
console.log('성공:', response);
// 성공 시 로직 처리
},
error: function(xhr, status, error) {
console.error('에러 발생:', xhr.status, error);
if (xhr.status === 415) {
alert('서버에서 지원하지 않는 데이터 형식입니다. Content-Type을 확인해주세요.');
}
// 에러 처리
}
});
// 예시: Fetch API 사용 시
fetch('/api/resource', {
method: 'POST',
headers: {
'Content-Type': 'application/json' // Content-Type 명시!
// 'Accept': 'application/json' // 서버로부터 어떤 타입의 응답을 받을지 명시 (선택 사항)
},
body: JSON.stringify(jsonData) // 데이터를 반드시 JSON 문자열로 변환!
})
.then(response => {
if (!response.ok) {
// 응답 상태가 2xx가 아닌 경우
if (response.status === 415) {
console.error('415 Unsupported Media Type 에러 발생!');
// 사용자에게 적절한 안내 메시지 표시
}
// 에러 객체를 throw하여 catch 블록에서 처리하도록 함
throw new Error(`Network response was not ok: ${response.status} ${response.statusText}`);
}
return response.json(); // 응답을 JSON 형태로 파싱
})
.then(data => {
console.log('성공:', data);
// 성공 시 로직 처리
})
.catch(error => {
console.error('Fetch 에러:', error);
// 에러 처리
});
꿀팁!
JSON.stringify()
를 잊지 마세요! JavaScript 객체를 서버로 보낼 때는 반드시 문자열 형태로 변환해야 합니다.
2. 서버야, 너도 혹시 편식하니? (서버 측)
클라이언트가
Content-Type
을 올바르게 보냈다면, 이제 서버가 해당
Content-Type
을 제대로 처리할 수 있도록 설정되어 있는지 확인해야 합니다.
- Java Spring 환경 예시:
- 만약
@RequestBody를 사용하여 JSON 데이터를 받으려고 한다면, 클라이언트는 반드시Content-Type: application/json으로 요청해야 합니다. - 클라이언트가 전통적인 HTML 폼 방식(
application/x-www-form-urlencoded)으로 데이터를 보내고, 서버에서는 이를 객체로 받아야 한다면@RequestBody대신@ModelAttribute어노테이션을 사용하는 것을 고려해 보세요. 또는, 클라이언트 측에서 JavaScript를 사용하여 데이터를 JSON 형태로 가공하여 전송하도록 수정해야 합니다. - Spring Boot는
MappingJackson2HttpMessageConverter와 같은 메시지 컨버터가 자동으로 JSON 변환을 처리해 주지만, 이는Content-Type헤더가application/json으로 정확히 명시되었을 때 동작합니다. 만약 다른 메시지 컨버터(예: XML용)가 필요하다면 의존성을 추가하고 설정해야 할 수 있습니다.
- 만약
- Node.js (Express.js) 환경 예시:
- JSON 요청 본문을 처리하기 위해서는
express.json()미들웨어를 반드시 사용해야 합니다. 이 미들웨어가 들어오는 요청의Content-Type이application/json인지 확인하고, 맞다면req.body에 파싱된 JSON 데이터를 넣어줍니다.
서버가 ${PORT}번 포트에서 실행 중입니다.));`` * 만약express.json()미들웨어를 등록하지 않거나, 클라이언트가Content-Type을application/json으로 보내지 않으면req.body는undefined`가 될 수 있고, 이로 인해 예상치 못한 오류가 발생하거나, 서버 설정에 따라 415 에러가 발생할 수 있습니다. - JSON 요청 본문을 처리하기 위해서는
- app.post('/api/data', (req, res) => { // express.json() 미들웨어 덕분에 req.body에 파싱된 JSON 데이터가 들어옵니다. // 또는 express.urlencoded() 미들웨어 덕분에 폼 데이터가 req.body에 들어옵니다. console.log('수신된 데이터:', req.body); res.status(200).send('데이터를 성공적으로 받았습니다!'); });
- // JSON 요청 본문을 파싱하기 위한 미들웨어 설정 // 이 미들웨어는 Content-Type 헤더가 'application/json'인 요청에 대해서만 동작합니다. app.use(express.json());
- 기타 서버 환경: 사용하는 프레임워크나 라이브러리가 특정
Content-Type을 처리하기 위한 별도의 설정이나 모듈(예:body-parser의 다른 옵션, XML 파서 라이브러리 등)을 필요로 하는지 확인하고 적용해야 합니다.
3. 클라이언트야, 네가 보낸 데이터, 진짜 그 형식 맞아? (요청 본문 형식 확인)
가끔은
Content-Type
헤더는
application/json
으로 잘 설정해놓고, 정작 보내는 데이터가 유효한 JSON 형식이 아닌 경우가 있습니다. 예를 들어, JSON 문자열 마지막에 쉼표(
,
)가 있다거나, 따옴표가 제대로 닫히지 않은 경우 등입니다. 이런 경우 서버는 데이터를 제대로 파싱하지 못해 400 Bad Request 에러를 반환하기도 하지만, 상황에 따라 415 에러의 간접적인 원인이 되기도 합니다.
- JSON 유효성 검사기 (JSON Validator) 등을 사용하여 보내려는 데이터가 문법적으로 올바른지 확인해 보세요.
4. API 사용 설명서는 읽어봤니? (API 문서 확인)
외부 API를 사용하거나, 팀 동료가 만든 API를 호출할 때 415 에러가 발생한다면, 가장 먼저 해당 API의 공식 문서를 꼼꼼히 살펴보세요.
- 서버가 어떤
Content-Type을 지원하는지 명시되어 있을 것입니다. - 요청 본문(payload)은 어떤 형식과 구조로 보내야 하는지 예시와 함께 설명되어 있을 가능성이 높습니다.
5. 혹시 중간에서 누가 장난치는 거 아니야? (프록시 또는 웹 서버 설정 확인)
드물지만, 우리 애플리케이션 서버 앞단에 위치한 프록시 서버(예: Nginx, Apache)나 웹 서버가 특정
Content-Type
의 요청을 차단하거나, 요청 헤더를 임의로 변경하는 경우가 있을 수 있습니다. 이러한 인프라 설정도 한 번쯤 점검해 볼 필요가 있습니다.
🛠️ 실전! 415 에러 상황별 대처법 (구체적인 시나리오)
이론은 이제 충분합니다! 실제 개발 현장에서 마주칠 수 있는 구체적인 시나리오와 해결 방법을 살펴봅시다.
시나리오 1: Spring Boot에서
@RequestBody
사용 시, 순진한 HTML 폼 데이터 전송으로 인한 눈물의 415 에러 😭
- 문제 상황:
- 클라이언트: 일반적인 HTML
을 사용하여POST방식으로 데이터를 전송. - 서버 (Spring Boot Controller):
java @PostMapping("/users") public ResponseEntity createUser(@RequestBody UserDto userDto) { // 유저 생성 로직 UserDto createdUser = userService.createUser(userDto); return ResponseEntity.status(HttpStatus.CREATED).body(createdUser); }
- 클라이언트: 일반적인 HTML
- 원인 분석: HTML 폼의 기본
Content-Type은application/x-www-form-urlencoded입니다. 하지만 서버의@RequestBody UserDto userDto는Content-Type이application/json인 요청을 기대하고 있습니다. 이 불일치로 인해 Spring은 요청 본문을UserDto객체로 변환하지 못하고 415 에러를 반환합니다. - 해결 방법:
- 클라이언트 수정 (권장✨): JavaScript(주로 AJAX 또는 Fetch API)를 사용하여 폼 데이터를 가져온 후, 이를 JSON 객체로 만들고
Content-Type: 'application/json'헤더와 함께 전송합니다. - ```
- ```html
- 서버 수정 (상황에 따라 고려): 만약 반드시
application/x-www-form-urlencoded형태의 폼 데이터를 그대로 받아야 한다면, Spring Controller에서@RequestBody대신@ModelAttribute어노테이션을 사용합니다.@ModelAttribute는 폼 데이터의 각 필드를 객체의 필드에 바인딩해줍니다. java @PostMapping("/users/form") public ResponseEntity createUserFromForm(@ModelAttribute UserDto userDto) { // @ModelAttribute는 application/x-www-form-urlencoded 데이터를 처리 UserDto createdUser = userService.createUser(userDto); return ResponseEntity.status(HttpStatus.CREATED).body(createdUser); }이 경우 클라이언트는 특별히Content-Type을application/json으로 변경할 필요 없이 일반적인 폼 제출을 하면 됩니다.
- 클라이언트 수정 (권장✨): JavaScript(주로 AJAX 또는 Fetch API)를 사용하여 폼 데이터를 가져온 후, 이를 JSON 객체로 만들고
시나리오 2: Postman 같은 API 테스트 도구 사용 시, 깜빡하고
Content-Type
헤더를 설정하지 않았을 때 🤦
- 문제 상황: Postman과 같은 API 테스트 도구를 사용하여
POST요청을 보내려고 합니다. Body 탭에서raw를 선택하고 JSON 데이터를 열심히 입력했습니다. 하지만 Headers 탭에서Content-Type을application/json으로 설정하는 것을 잊고 요청을 보냈습니다. - 원인 분석:
Content-Type헤더가 없거나, Postman의 기본값(예:text/plain)으로 설정되어 서버로 전송되면, 서버는 이 요청 본문이 JSON인지 알 수 없습니다. 따라서 서버는 "이게 무슨 데이터인지 모르겠어!"라며 415 에러를 반환합니다. - 해결 방법: 아주 간단합니다! Postman의 Headers 탭으로 이동하여 다음을 추가합니다.
- KEY:
Content-Type - VALUE:
application/json(또는 실제 전송하는 데이터 형식에 맞는 타입, 예를 들어 XML이라면application/xml)
이렇게 설정하고 다시 요청을 보내면, 서버는 이제 요청 본문이 JSON 데이터임을 인지하고 정상적으로 처리할 가능성이 매우 높아집니다.KEY VALUE Content-Type application/json - KEY:
✨ 415 에러, 이제 두렵지 않아! (요약 및 마무리)
415 Unsupported Media Type 에러는 결국 클라이언트와 서버 간의 "데이터 형식"에 대한 소통 부재 로 인해 발생하는 경우가 대부분입니다.
- 클라이언트는 자신이 보내는 데이터가 어떤 형식인지
Content-Type헤더를 통해 명확하게 알려줘야 하고, - 서버는 자신이 이해하고 처리할 수 있는
Content-Type을 올바르게 설정하고, 해당 형식의 데이터를 처리할 준비가 되어 있어야 합니다.
마치 우리가 대화할 때 서로 같은 언어를 사용해야 소통이 원활한 것처럼, 웹 통신에서도 클라이언트와 서버는
Content-Type
이라는 '언어'를 맞춰야 합니다.
이 글에서 제시된 원인 분석과 해결 방법들을 차근차근 따라 해 보시면, 지긋지긋했던 415 에러도 생각보다 쉽게 해결할 수 있다는 것을 깨닫게 되실 겁니다. 이제 더 이상 415 에러 메시지 앞에서 당황하지 마시고, 자신감을 가지고 문제를 해결해나가시길 바랍니다! 여러분의 성공적인 개발 여정을 응원합니다! 🎉