[TroubleShooting] Content-type: x-www-form-urlencoded에서 POST 데이터 보내기
Web Frontend Developer

[TroubleShooting] Content-type: x-www-form-urlencoded에서 POST 데이터 보내기

오늘은 최근에 내가 개발을 하면서 몇 시간동안 고민한 이슈에 대한 정리를 해 보려고 한다.

이 이슈는 내가 어떤 회사에 입사하기 위해 치뤘던 코딩 과제를 하는 도중에 발생하였다. 다행히도 이 과제 기한을 48시간을 주어서, 몇 시간 삽질을 해도 완성 후 제출할 수 있었으나, 만약에 짧은 시간에 해결을 해야 하는 경우였다면 문제를 해결하지 못했을 것이다. 내가 했던 삽질을 앞으로 나를 포함한 누구도 하지 않고 시간을 아끼기 위한 마음에 내용을 정리해 보고자 한다.

먼저 나는 REST API가 구현된 서버 코드를 이미 받은 상태였고, 이미 잘 구현된 API를 그래도 가져다 쓰기만 하면 되는 것이었다. README에 명세된 API는 다음과 같은 조건을 가지고 있었다.

POST 메서드로 Content-Type은 x-www-form-urlencoded 이며, Input 데이터를 다음과 같은 JSON Array, 이 때 value는 Stringify 해서 보내야 한다고 되어 있었다. 그래서 나는 너무나도 자연스럽게 JSON 형태의 변수에 key = "input", value = JSON Array 형식으로 만들어서 그 변수를 JSON.stringify()해서 서버에 보내주었다.

너무나도 문제 없이 실행 될 것이라 예상했는데, 계속해서 에러가 나왔다. 디버깅 하는 도중 내가 보낸 데이터가 JSON.parse() 되어서 다음과 같은 형태로 콘솔에 찍히는 것을 발견하였다.

글씨가 작아서 잘 안 보이실 수도 있는 분들을 위해 설명하면, 내가 원했던 것은 내가 보낸 data가 JSON.parse(data)를 하면 key가 input이고, value가 JSON Array인 형태로 나오는 것이었다. 그런데 콘솔을 보니 키값이 '{"input":' 이라는 값이었고, value도 Array가 아닌 그냥 문자열로 나타나게 되었다.

나는 이 이슈를 몇 시간 동안 고민을 해서 이 방법 저 방법 다양하게 시도해 보았지만 원하는 결과를 얻을 수 없었다. 그러다가 한 지인의 도움을 받아 이슈를 해결하게 되었는데 나는 단지 한 줄만(정확히는 두 줄) 바꾸어 주고 이슈를 해결하게 되었다.

// 기존 코드
let submitAnswer = {
  input: []
};
...
xhr.send(JSON.stringify(submitAnswer));

// 해결 코드
let submitAnswer = [];
...
xhr.send('input=' + encodeURIComponent(JSON.stringify(submitAnswer)));

이렇게 하니까 마법처럼 문제가 해결이 되었다. 그렇게 과제를 성공적으로 제출하고 나는 이 이슈를 내가 왜 해결하지 못 했는지에 대해서 곰곰하게 생각해 보았다.

Content-type은 해당 포맷으로 POST data를 보내 달라는 의미이다. 나는 application/json이 아닌 application/x-www-form-urlencoded 타입으로 데이터를 보내야 했다. 공식 문서를 찾아보면 application/x-www-form-urlencoded 타입에 대해 다음과 같은 설명이 나와 있다.

https://developer.mozilla.org/ko/docs/Web/HTTP/Methods/POST

 

POST

HTTP POST 메서드는 서버로 데이터를 전송합니다. 요청 본문의 유형은 Content-Type 헤더로 나타냅니다.

developer.mozilla.org

application/x-www-form-urlencoded: &으로 분리되고, "=" 기호로 값과 키를 연결하는 key-value tuple로 인코딩되는 값입니다. 영어 알파벳이 아닌 문자들은 percent encoded 으로 인코딩됩니다. 따라서, 이 content type은 바이너리 데이터에 사용하기에는 적절치 않습니다. (바이너리 데이터에는 use multipart/form-data 를 사용해 주세요.)

해당 데이터는 "=" 기호로 값과 키를 연결하는 key-value tuple로 인코딩되는 값이라고 너무나도 친절하게 잘 나와 있다.

https://stackoverflow.com/questions/4007969/application-x-www-form-urlencoded-or-multipart-form-data

 

application/x-www-form-urlencoded or multipart/form-data?

In HTTP there are two ways to POST data: application/x-www-form-urlencoded and multipart/form-data. I understand that most browsers are only able to upload files if multipart/form-data is used. Is ...

stackoverflow.com

스택오버플로우 답변을 봐도 나와있다. binary data는 전송 시 multipart/form-data를 사용하고, 그렇지 않은 경우에는 application/x-www-form-urlencoded를 사용하라고 나와있다. 그리고 application/x-www-form-urlencoded는 서버에 전송되는 HTTP 메시지가 하나의 큰 쿼리 스트링이고 이름/값 쌍들이 "&"로 구분되어 있으며, 이름과 값은 "="으로 구분된다고 나온다. 

이렇듯 잘 찾아보면 이번 이슈를 해결할 수 있는 자료는 구글에 얼마든지 있었다. 다음에는 이와 같은 삽질은 몇 시간 동안 할 필요가 없도록, 이슈가 생겼을 때 원인이 무엇인지 빠르고 정확하게 파악하는 연습을 해야 겠다.