HTTP
1. Serialization
- 직렬화 : 메모리 상에 저장된 데이터를 전송 가능한 형태로 바꾸는 작업.
Heap 메모리 내에 표현되어 있는 데이터는 읽을 수 없는 형태로 저장되어 있다.. >> 읽을 수 있는 글귀로 형식에 맞춰 표현하는 것을 직렬화라고 한다.
- JSON (JavaScript Object Notation)
: Lightweight data-interchange format. 데이터를 주고받는데 활용할 수 있는 데이터 표현 방식.
- JavaScript 객체를 표현하는 방식에서 그 문법을 차용.
- 중괄호 내부에 Key-Value쌍을 콜론으로 구분.
- 사람이 읽고 쓰기 쉬움 / 기계가 파싱(해석)하고 만들기 편함
- 거의 대부분의 API 통신에서 사용.
2. @RequestMapping
- 클라이언트의 요청이 들어왔을 때 @RequestMapping에 전달한 설정에 일치할 경우 실행할 메서드를 설정한다.
@Slf4j
@Controller
public class MappingController {
// @RequestMapping에 전달된 파라미터를 바탕으로
// 어떤 http 요청에 대해 메서드가 실행되는지
@RequestMapping(
value = "/example/{pathVar}",
method = {RequestMethod.GET, RequestMethod.POST},
// 요청의 Content-Type 헤더
consumes = MediaType.APPLICATION_JSON_VALUE,
// headers : 어떤 headers가 포함되어야 실행이 되는지
headers = "x-headers-example=hello",
// params : 어떤 Query 파라미터가 있어야하는지
params = "param-example=hello"
)
@ResponseBody
public String example(@PathVariable String pathVar) {
return "done";
}
}
- value : 요청 url의 path
- method : 요청의 HTTP Method. 복수로 설정도 가능함. (Get요청, Post요청 둘다 이 메서드로 들어오게 된다)
- headers : 요청 헤더
- params : 요청 쿼리 파라미터
- produces/ consumes : 요청/응답으로 주고받는 데이터 형식(Content-Type)을 전하는 용도
3. HTTP 메시지 다루기
1) @RequestHeader
: 사용자 요청의 헤더를 가지고 오고 싶을 때 활용.
- 개별 헤더를 가져와 메서드의 인자로 할당하는 방식. >> 인자로 확인하고 싶은 헤더를 전달.
- 해당하는 헤더가 요청에 포함되어 있지 않으면 > 400 응답이 나오는데, 선택적으로 포함해야 되는 헤더라면 required=false를 추가.
- 반드시 인자의 자료형이 문자열일 필요는 없음. > 헤더가 어떤 자료형인지 안다면 해당 타입으로 선언 가능. >> 타입이 일치하지 않으면 400이 반환됨.
- defaultValue로 기본값을 설정할 수도 있다.
@PostMapping("/option-header")
@ResponseBody
public String optionHeader(
@RequestHeader(
value = "x-example",
// required: 포함을 반드시 해야하는지
required = false
)
String example, // Integer example로도 가능
@RequestHeader(
value = "x-example-default",
required = false,
// defaultValue: 포함안되었을때 기본값
defaultValue = "hello"
)
String exampleDefaultHeader
) {
log.info(examplenHeader);
log.info(exampleDefaultHeader);
return exampleDefaultHeader;
}
- 전송된 모든 헤더를 하나의 인자로 할당하는 방식.
: HttpHeaders / Map<String, String> / MultiValueMap<String, String> 로 담을 수 있다.
@PostMapping(
"/headers"
)
public String getHeaders(
@RequestHeader HttpHeaders headers,
@RequestHeader Map<String, String> headerMap,
@RequestHeader MultiValueMap<String, String> headerMvMap
) {
headers.forEach((key, value) -> log.warn(String.format("%s: %s, %s", key, value, value.getClass())));
headerMap.forEach((key, value) -> log.warn(String.format("%s: %s, %s", key, value, value.getClass())));
headerMvMap.forEach((key, value) -> log.warn(String.format("%s: %s, %s", key, value, value.getClass())));
log.info("POST /headers");
return "index";
}
2) @RequestBody / @ResponseBody
: 요청과 응답의 Body 형태를 결정하는 어노테이션
- 클라이언트가 보낸 데이터의 필드가 지정된 객체와 동일할 경우 그 데이터를 할당해서 객체를 만들어줌.
- @RequestBody : 클라이언트가 보낸 HTTP Body의 데이터가 지정된 객체(ArticleDto)의 필드와 일치할 때 해당 데이터를 객체화하여 메서드의 인자로 할당.
- @ResponseBody : 메서드 자체에 지정하여 반환값에 대하여 작동. View가 아니라 지정된 객체를 JSON을 비롯한 데이터로 변환하여 응답.
- ** @RestController를 사용하면 > 모든 메서드에 @ResponseBody가 추가된다.
@RestController
public class ArticleController {
@PostMapping("/dto")
@ResponseBody
// 메서드의 반환값을 View로 취급하지 않고, 순수한 전달될 HTTP Response로 취급하는 어노테이션
public ArticleDto body(@RequestBody ArticleDto dto) {
log.info("POST /dto, body: " + dto.toString());
LocalDateTime now = LocalDateTime.now();
dto.setCreatedAt(now);
dto.setUpdatedAt(now);
return dto;
}
3) ResponseEntity
: 좀더 세밀한 응답 조절이 필요할 때 반환형으로 ResponseEntity를 사용. (@ResponseBody 생략)
- ResponseEntity는 제네릭 타입으로 응답 타입을 그대로 활용하는데 도움.
- 응답 상태 코드를 지정하거나,,,
@PostMapping("student/entity")
public ResponseEntity<MessageDto> postEntity(
@RequestBody
StudentDto studentDto
) {
log.info(studentDto.toString());
MessageDto messageDto = new MessageDto();
messageDto.setMessage("등록 완료");
return new ResponseEntity<>(messageDto, HttpStatus.CREATED);
}
// 결과 Status 201 Created
- 응답에 추가하고 싶은 Header를 포함시키는 등... 세밀하게 응답 조정이 가능!
@PostMapping("student/entity")
public ResponseEntity<MessageDto> postEntity(
@RequestBody
StudentDto studentDto
) {
log.info(studentDto.toString());
MessageDto messageDto = new MessageDto();
messageDto.setMessage("등록 완료");
// headers 설정
HttpHeaders headers = new HttpHeaders();
headers.add("x-example-response", "okay");
headers.add("x-example-name", "hehesim");
return new ResponseEntity<>(messageDto, headers, HttpStatus.ACCEPTED);
}
+ status빌더와 함께 빌더 메서드로도 표현이 가능.
@GetMapping("student/bad-request")
public ResponseEntity<MessageDto> badRequest(
@RequestBody
StudentDto studentDto
) {
log.info(studentDto.toString());
MessageDto messageDto = new MessageDto();
if (studentDto.getAge() < 10) {
messageDto.setMessage("너무 어려요");
// return new ResponseEntity<>(messageDto, HttpStatus.BAD_REQUEST);
return ResponseEntity.badRequest()
.header("x-example-response", "bad request")
.body(messageDto);
} else {
messageDto.setMessage("ok");
// return new ResponseEntity<>(messageDto, HttpStatus.OK);
return ResponseEntity.badRequest()
.header("x-example-response", "ok")
.body(messageDto);
}
** Handler Method
Method Arguments :: Spring Framework
Method Arguments :: Spring Framework
JDK 8’s java.util.Optional is supported as a method argument in combination with annotations that have a required attribute (for example, @RequestParam, @RequestHeader, and others) and is equivalent to required=false.
docs.spring.io
'Programming > Network' 카테고리의 다른 글
HTTP (2) | 2024.11.29 |
---|---|
URI와 웹 브라우저 요청 흐름 (0) | 2024.11.26 |
인터넷 네트워크 (4) | 2024.11.23 |
Web (0) | 2024.01.16 |
인터넷 네트워크 정리 (0) | 2023.09.14 |