개발/개발노트

[Network] application/x-www-form-urlencoded 와 application/json의 흐름

Gamii 2024. 3. 28. 19:13
728x90

 

 

 

클라이언트에서 서버로 요청할 때, Ajax를 많이 이용한다. 보통은 Json으로만 사용해서 Ajax에는 application/json을 명시하고 서버에서는 dto를 만들어 @RequestBody를 사용했다. 당연하게 사용했던 부분에 대해 "application/json 일 때는 왜 @ResquestBody로만 받아야 할까?", "application/x-www-form-urlencoded 일 경우는 @RequestBody로 받지 못할까" 등 궁금증이 생겨서 흐름을 정리해 보려고 한다.

 

 


 

[개념]

0. HTTP의 구조

application/x-www-form-urlencoded와 application/json의 흐름을 설명하기 위해서는 간략하게 HTTP 구조를 알아야 한다. HTTP는 Request Line(Start Line), Request Headers, Empty Line, Request Message Body로 나눠진다.

https://hazel-developer.tistory.com/145

 

 

 

 

1. Ajax 기본 형태

 

$.ajax({    
	type : 'POST',
	url : '/test.do',
	async : true,
	dataType : 'json',
	contentType: 'application/json',
	data : JSON.stringify({
			"no" : 142,
			"name" : "Kim",
			"nick" : "K"    
	}),
	success : function(result) {
		// 결과 성공 콜백함수        
		console.log(result);    
	},
	error : function(request, status, error) { 
		// 결과 에러 콜백함수        
		console.log(error)    
	},
	complete: function (){
		// 완료 후 콜백함수
	}
})

 

 

현재 Ajax를 사용하고 있어서, Ajax 기반으로 작성하려고 한다. HTTP 통신을 위해 다룰 옵션은 contentType, data, dataType이다. (POST 요청으로 가정)

 

 

1) data

- contentType이 application/json일 때, 당연히 파라미터 값들도 JSON 형식이어야 한다.

- 위 예제처럼, JSON 객체의 stringify() 메서드를 사용하면 JavaScript 객체를 JSON 문자열로 변환이 되어 보내지는 것을 확인할 수 있다. ( 예시 - JSON.stringify(param))

 

 

 

 

2) dataType

- Ajax를 통해 리턴 받을 데이터의 타입을 성정하는 옵션이다.

- 설정하지 않으면, default로 MIME 타입을 참고하여 자동 파싱된다.

- 종류 : xml, html, script, json, text

 

 

 

3) contentType

- contentType은 HTTP Header의 일부로, 전송되는 데이터의 유형을 지정하는 데 사용된다. 클라이언트와 서버 간의 어떤 유형의 데이터가 전송되고 있는지 알려주고, 수신하는 쪽에서 그에 맞게 데이터를 올바르게 처리할 수 있다.

 

- Ajax에서는 contentType 옵션에 넣어준 값이 HTTP Header로 보내지게 된다. 설정을 하지 않으면, default로 " application/x-www-form-urlencoded"가 설정된다.

 

 

 

 

 


 

 

application/x-www-form-urlencoded과 application/json

자주 사용하는 Content Type인 application/x-www-form-urlencoded와 application/json에 대해 얘기해보려고 한다.

 

 

[application/x-www-form-urlencoded]

HTTP 통신에서 주로 사용되는 Content-Type 중 하나로, HTML의 form 데이터를 URL 인코딩하여 전송할 때 사용된다. 이 형식은 특히 Web form을 통해 데이터를 서버에 전송할 때 많이 사용된다.

 

 

URL 인코딩이 되면 아래와 같이 key와 value는 = 기호로 연결되고, 여러 쌍은 & 기호로 구분된다. 그리고 공백은 + 기호로 인코딩 된다.

//key=value&key=value의 형태
name=John&age=30&city=New+York

 

 

 

서버에서는 @RequestParam 어노테이션을 활용해서 데이터를 받을 수 있다.

@RequestMapping(value = "/test.do", method= RequestMethod.POST)
public String testIndex2(@RequestParam Map<String, Object> map) {
    System.out.println("map2 = " + map);
    return "testIndex2";
}

 

 

 

 

[application/json]

요즘은 JSON 형식의 데이터를 많이 사용하는 걸 볼 수 있다. {key:value, key:value } 형식으로 Message Body에 담겨 서버로 전달된다. JSON 형식은 객체(Object), 배열(Array), 문자열(String), 숫자(Number), 불리언(boolean), null 등 다양한  데이터 타입을 포함한다.

//1. 객체(Object)
{
    "name" : "John",
    "age" : 30,
    "city" : "New York"
}

//2. 배열(Array)
[
    "apple",
    "banana",
    "grape"
]

 

 

 

서버에서는 @RequestBody 어노테이션을 활용해 JSON Object, Array 데이터를 받을 수 있다.

//application/json 으로 받을 때

//JSON Object로 받을 때
@RequestMapping(value = "/test.do", method= RequestMethod.POST)
public String testIndex(@RequestBody Map<String, Object> map) {
    System.out.println("map1 = " + map);

    return "testIndex";
}

//JSON Array로 받을 때
@RequestMapping(value = "/test.do", method= RequestMethod.POST)
public String testIndex(@RequestBody List<Object> list) {
    System.out.println("list1 = " + list);

    return "testIndex";
}

 

 

 

 


[질문]

 

Q. @RequestBody를 이용해서 application/x-www-form-urlencoded 데이터를 받을 수 없을까?

 

 

MultiValueMap 클래스를 이용해 받는 방법이 있다. 하지만 원하는 형태로 받아지지 않아서 @RequestParam이나 @ModelAttribute를 사용하면 원하는 형식으로 받을 수 있다. 

@PostMapping(value = "/test.do")
public String testIndex(@RequestBody MultiValueMap<String, Object> map) {
	System.out.println("map = " + map);
    
    return "testIndex";
}

//결과
// map = {no=[142], name=[Kim], nick=[K]}

 

 

 

@RequestBody에서 message convert를 이용해 인스턴스로 변환시켜 주는데, ContentType이 application/x-www-form-urlencoded인 요청을 Map클래스나 VO 타입의 인스턴스로 변환해 주는 Message converter가 없기 때문이다.

FormHttpMessageConverter가 application/x-www-form-urlencoded인 요청을 MultiValuedMap타입의 인스턴스로 변환해 주는 역할을 한다. (기본으로 내장)

 

 

 


 

 

[Tip - 1] Ajax에서 JSON으로 서버와 통신하기 위해서 확인해야 할 옵션 3가지

1) contentType : 'application/json'

 

2-1) JSON 객체일 경우

data : JSON.stringify({

                  "user_id" : 1.

                  "name" : "testUser"

          });

 

2-1) JSON Array일 경우

data : JSON.stringify(["apple", "banana", "grape"]);

 

3) type : "POST"

 

 

 

 

 

[Tip - 2] 서버에서 Content Type 별로 받을 수 있는 코드

@RestController
public class TestController {
    //Content Type별 메소드

    //application/json 으로 받을 때
    @RequestMapping(value = "/test.do", method= RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
    public String testIndex(@RequestBody Map<String, Object> map) {
        System.out.println("map1 = " + map);

        return "testIndex";
    }

    //application/x-www-form-urlencoded (form)으로 받을 때
    @RequestMapping(value = "/test.do", method= RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    public String testIndex2(@RequestParam Map<String, Object> map) {
        System.out.println("map2 = " + map);
        return "testIndex2";
    }
}

 

 

 

 


[참고]

 

 

Ajax와 @RequestBody, @ResponseBody

너무 단순한 주제지만 프로젝트를 분석하다보면 잘못 사용된 경우도 있고 나도 제대로 알지 못하고 사용했던 부분이 있어 정리해놓는다. 우선 아래와 같은 Controller 메소드가 있다고 가정해보자

findmypiece.tistory.com

 

 

[Spring] Post 요청과 Content-Type의 관계

실무에서 RestAPI를 만들면서 간혹 마주치는 이슈가 있었다. Client에서 POST 방식으로 요청을 보...

blog.naver.com