GET / PUT / POST / PATCH / DELETE
HTTP "프로토콜"
HTTP(Hyper Text Transfer Protocol)
웹브라우저와 웹서버간의 통신을 위한 표준
클라이언트가 요청(request)을 보내면, 서버는 응답(response)을 돌려주는 방식으로 동작한다
HTTP는 무상태성(Stateless)을 특징으로 하며, 각각의 요청(요청과 응답)은 서로 독립적이다.
요청과 응답 구조
클라이언트 컴퓨터는 브라우저라는 웹 어플리케이션을 이용해 웹 서버를 가지고 있는 컴퓨터에게 요청함.
요청을 받은 웹 서버는 해당 요청에 대한 응답을 클라이언트에게 보내준다.
클라이언트(크롬, 사파리, 인터넷 익스플로러 등)와 웹 서버(AWS, 아파치 등)간에 데이터를 교환하고 통신하기 위해서는 표준이 필요한데, 이 표준 규칙이 바로 TCP/IP 이다.
HTTP는 TCP/IP의 하위 항목 중 하나로, html과 같은 문서를 주고 받을 때 사용하는 규칙임.
웹서버에게 url을 넘기며 요청하면 미리 지정된 html파일이 브라우저에 보이는 것 뿐만 아니라,
하나의 html 파일에서도 웹 서버에 여러 개의 요청을 보낼 수 있다.(링크를 클릭하면 css, 이미지, 비디오파일 등 불러오기)
HTTP에서 각 요청은 독립적이여서 같은 컨텍스트임에도 계속해서 새로운 연결을 시도하기 때문에 성능문제가 발생할 수 있고,
이 때문에 자주 사용하는 것들을 한데 모아서 미리 가져다 쓰는 cookie 등을 사용한다.
1) HTTP 요청(Request) 구조
요청 줄(Start Line)
GET /products HTTP/1.1
Method : 클라이언트가 수행하려는 작업의 종류(GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, ...)
Request Target : 요청 대상의 경로 (/products)
HTTP version : 사용중인 HTTP 프로토콜 버전 (HTTP/1.1)
요청 헤더(Headers)
헤더는 key - value 쌍으로 이루어지며 요청에 대한 추가 정보를 제공한다. 보통 Map형태로 전달한다. 형태만 알아두자.
유형
General : 메세지 전체에 영향을 줌 (ex : Connenction: keep-alive)
Request : 브라우저, 클라이언트 정보 (ex : User-Agent, Accept)
Representation : Body의 포맷 지정 (ex : Content-Type)
Body(본문)
GET : 보통 Body가 없음
POST, PUT : JSON, Form, 파일 등 포함할 수 있음
"{
"name": "블러퍼",
"email": "B1uffer@test.com"
"}
위 형태가 JSON 형태라고 함 매우 자주 쓰고 앞으로 쓰게 될 것이다.
2) HTTP 응답(Response) 구조
상태 줄(Status Line)
HTTP/1.1 200 OK
Version : HTTP/1.1
Status Code : 200 (정상작동)
Reason Phrase : OK
응답 헤더
유형
General : 메세지 전체 설정(Connection : close)
Response : 서버의 정보(Server : nginx)
Representation : Body의 포맷(Content-Type : application/json)
본문(Body) : 응답 본문은 HTML, JSON, XML, 파일 등 다양하게 존재할 수 있다고 한다.
{
"result": "success",
"data": {
"id": 123,
"name": "홍길동"
}
}
위의 JSON 형태는 공부했던 Map<String, Map<String, String>> 이런 형태로 보인다. 이걸 자주 쓰더라구..
* 204 No Content, 304 Not Modified 응답에는 Body가 없을 수 있다고 한다.
주요 HTTP 메서드 (중요)
HTTP는 리로스의 목적과 행위의 의도에 따라 다양한 메서드를 정의한다.
RESTful API 설계에서도 이 메서드의 의미에 따라 요청을 구분하고,
Spring MVC에서는 @GetMapping, @PostMapping, @PutMapping 등의 어노테이션으로 이를 명확하게 구분하여 처리한다.
메서드 / 설명 / 특징 / 대표 사용 예
GET / 리소스를 조회한다 / Body 없음, 캐싱 가능 / 게시글 목록 조회, 유저 정보 요청
POST / 리소스를 생성함 / Body 필수, 중복 요청 시 동일 리소스 생성 가능 / 게시글 작성, 회원가입
PUT / 리소스 전체를 수정함 / 대상이 없으면 생성된다(idempotent, 멱등성) / 게시글 전체 내용을 수정함
PATCH / 리소스를 일부 수정함 / 일부 필드만 전송 가능하다 / 게시글 제목만 수정, 비밀번호 변경하기
DELETE / 리소스를 삭제함 / Body가 거의 없다 / 게시글 삭제, 회원 탈퇴
// GET - 목록 조회
@GetMapping("/posts") // 이 Mapping을 통해 브라우저 주소를 찾아간다
public List<Post> getPosts() {
return postService.findAll();
}
// POST - 리소스 생성
@PostMapping("/posts")
public void createPost(@RequestBody Post post) { // @RequestBody
postService.save(post);
}
// PUT - 리소스 전체 수정
@PutMapping("/posts/{id}")
public void updatePost(@PathVariable Long id, @RequestBody Post post) { @PathVariable
postService.update(id, post);
}
// PATCH - 리소스 일부 수정
@PatchMapping("/posts/{id}")
public void patchPost(@PathVariable Long id, @RequestBody Map<String, Object> updates) {
postService.patch(id, updates);
}
// DELETE - 리소스 삭제
@DeleteMapping("/posts/{id}")
public void deletePost(@PathVariable Long id) {
postService.delete(id);
}
@PostMapping, @PutMapping, @PatchMapping, @DeleteMapping
@PostMapping() 괄호 안에서 맵핑할 url을 적는다
그리고 만약 리턴값이 있다면 그 리턴값은 String? 일텐데 그 String값에 해당하는 html파일을 만들어야함
@RequestBody, @PathVariable
*** GET과 POST의 차이점
GET과 POST는 가장 자주 사용하는 HTTP 메서드로, 목적과 틍성이 분명하게 다르다.
| GET | POST | |
| 요청 목적 | 데이터 조회 | 데이터 생성, 제출 |
| 요청 데이터 위치 | URL 쿼리 스트링 | HTTP Body (Json/Form 등) |
| 요청 본문 | 없씀 | 있씀 |
| URL 길이 제한 | 있씀 (브라우저 제한 약 2,048자) | 없씀 (이론상 무제한) |
| 캐싱 | 가능 (브라우저/프록시 서버) | 기본적으로 불가능 |
| 멱등성 | O (같은 요청을 반복해도 결과가 같다) | X (중복 요청하면 리소스 중복 생성 가능) |
| 브라우저 뒤로가기 / 새로고침 | 안전하다 | 새로고침 시 재요청 주의 (재등록 가능성) |
| 보안 | 상대적으로 위험?(주소에 데이터 노출) | 상대적으로 안전? (본문에 포함된다) |
* 멱등성 : 같은 연산을 여러번 수행해도 결과가 같아야한다 라는 의미. 위의 PUT에 멱등성이라고 적혀있다.
어떤 작업을 1번 수행하든, 100번 수행하든 시스템의 상태나 결과가 변화지 않아야 멱등성(idempotency)을 가진다고 함
HTTP에서 멱등성
GET : 같은 리소스 요청이므로 여러번 호출해도 결과가 같다(멱등성)
PUT : 같은 자원에 같은 값을 덮어쓰기(멱등성)
DELETE : 이미 삭제된 리소스를 또 삭제해도 상태는 같다(멱등성)
POST : 매 호출마다 새로운 리소스를 생성할 수 있다. (멱등성 X)
PATCH : 일부 필드만 수정하여 여러번 수정 시 상태가 달라질 수 있다. (멱등성 X)
// GET 요청
GET /search?q=spring HTTP/1.1
Host: example.com
// POST 요청
POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded
{
"username": "lee",
"password":"1234"
}
- 검색 조회 등은 GET으로 처리하고, 캐시나 URL 공유 가능성이 있을때 유리하다
- 민감한 데이터 전송, 폼 전송 등은 반드시 POST로 처리해야한다.
- 리소스 생성/수정시 멱등성 여부도 고려해야한다
HTTP 상태코드 (왠만한건 알아둬야한다) ***
클라이언트의 요청에 대한 서버의 처리 결과를 숫자와 간단한 메세지로 표현한 것
서버는 응답 메세지의 첫줄(status line)에 상태코드를 포함해서 클라이언트에게 요청 처리 결과를 알린다
상태코드는 100~599의 숫자 코드임
400번부터 문제가 발생한다..
| 100~199 | 정보가 전달됨(거의 사용하지 않음) |
| 200~299 | 요청이 성공적으로 처리됨 |
| 300~399 | 리다이렉션(다른 위치로의 이동 유도) |
| 400~499 | 클라이언트(사용자) 오류, 요청 문제 |
| 500~599 | 서버(개발자쪽) 오류, 서버 내부 문제 |
대표적인 상태 코드들
200~299(요청이 성공적으로 처리됨)
| 200 OK | 요청 성공 | 대부분의 GET 요청 성공시 사용됨 |
| 201 Created | 리소스 생성됨 | POST 요청시 새 리소스가 만들어졌음 |
| 204 No Content | 본문이 없음 | 전달 성공했지만 반환 데이터가 없음 (DELETE 등등..) |
300~399(리다이렉션, 다른 위치로의 이동 유도)
| 302 Found | 일시적인 이동 | 임시로 다른 URL로 이동함(리다렉션) |
| 304 Not Modified | 변경이 없음? | 캐시된 리소스를 그대로 사용해도 된다? |
| 301 Moved Permenently | 영구적 이동 | URL이 변경되었으며 클라이언트는 새로운 URL을 요청해야만함 |
400~499(사용자 문제)
| 400 Bad Request | 잘못된 요청 | 필수 파라미터 누락, JSON 형식 오류 등.. |
| 401 Unauthorized | 인증 실패 | 로그인 또는 토큰이 없거나 잘못됨 |
| 403 Forbidden | 권한이 없음 | 인증은 됐으나 접근 권한이 없음 (관리자만 허용됐거나..) |
| 404 Not Found | 존재하지 않음 | 그녀석 URL 또는 리소스가 서버에 없음 |
| 409 Conflict | 충돌? | 리소스 중복, 상태 충돌 등으로 요청된 처리를 할 수 없음 |
| 415 Unsupported Media Type | 지원하지않는 형식 | Context-Type이 잘못된 경우 (XML 대신 JSON 필요) |
| 429 Too Many Requests | 요청 과다 | API 호출 한도 초과(rate limiting) |
500~599(서버 문제)
| 500 Internal Server Error | 서버 내부 오류 | 예외 발생 등 서버 코드 문제 |
| 502 Bad Gateway | 게이트웨이 오류 | 프록시 서버에서 백엔드 서버 응답 문제 발생 |
| 503 Service Unavailable | 서비스 불가 | 서버 과부하 또는 점검중 |
*500 Internal Server Error는 서버 코드에 예외가 발생했을 때 사용되며, 디버깅이 매우 중요한 코드이다.
Spring의 상태코드 설정 예시
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message)
}
}
// ResponseEntity로 명시적 설정.. 리턴 타입에 주의
return ResponseEntity.status(HttpStatus.CREATED).body(newUser);
Content-Type과 Accept 헤더의 역할
HTTP 통신에서는 클라이언트와 서버가 서로 어떤 형식의 데이터를 주고받을지 명확하게 합의해야하며,
이를 위해 사용하는게 Context-Type과 Accept 헤더라고 한다.
Context-Type과 Accept 두개의 헤더는 HTTP 요청/응답에서 데이터 포맷을 정의하거나 협상하는 역할을 한다.
API 설계에서 매우 중요하다고함.
뭔소린지 아직 모르겠다 일단 알아두자
| Content-Type | 요청 바디의 데이터 형식 정의 | 클라이언트가 서버에 보내는 데이터가 어떤 형식인지 명시함 |
application/json, application/x-www-form-asd |
| Accept | 응답 데이터 형식 요청 | 클라이언트가 서버로부터 어떤 형식의 응답을 받고 싶은지 제안 | application.json, text/html, application/xml |
Content-Type의 예시
POST /api/posts HTTP/1.1
Content-Type: application/json
{
"title": "게시글 제목",
"content": "본문 내용"
}
//
POST /submit HTTP/1.1
Content-Type: application/x-www-form-urlencoded
username=admin&password=1234
* 요청하니까 POST 형태
저 위에 있는 Content-Type에 적혀있는데 헤더이고,
그 위에 있는게 요청 줄 Start Line이다.
HTTP 요청/응답에서 데이터 포맷을 정의하거나 협상하는 역할을 하는게 이 헤더들이고
데이터 형식을 명시하는게 Content-Type이니까
위의 예시에서는 클라이언트가 서버에 application/x-www-form-urlencoded 형태의 데이터 형식으로 보낸다고 알려주는것
Accept 예시
GET /api/posts HTTP/1.1
Accept: application/json
* 응답하니까 GET 형태의 헤더
첫줄의 GET /api/posts HTTP/1.1도 상태 줄(Status Line)이 아니고 Start Line이다. HTTP 요청임
다음줄 Accept는 클라이언트가 서버로부터 어떤 형태의 응답을 받고 싶은지 요청하는거니까
클라이언트는 서버한테서 application/json 형태의 응답을 받고 싶은것이다.
Content-Type, Accept + Spring Boot
Content Type과 Accept 두 헤더를 기반으로 Spring Boot엣서는 자동 변환 및 직렬화 처리를 한다
클라이언트가 Content-Type: application/json으로 요청을 보내면 요청 바디의 JSON을 자바 객체로 변환한다
서버는 Accept: application/json에 따라 자바 객체를 JSON 문자열로 직렬화하여 응답한다
@PostMapping(value = "/posts",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
// produces가 Accept 헤더를 기반으로 응답 포맷을 결정한다
public ResponseEntity<Post> createPost(@RequestBody Post post) {
// @RequestBody가 Content-Type에 따라 요청 바디를 객체로 역직렬화하고
Post saved = postService.save(post);
return ResponseEntity.status(HttpStatus.CREATED).body(saved);
}
주요 Content-Type 정리
| application/json | JSON 형식 데이터 | 대부분의 REST API 요청/응답 |
| application/x-www-form-urlencoded | HTML form 전송 형식 | 로그인, 회원가입 등 |
| multipart/form-data | 파일 업로드시 사용 | 이미지, 첨부파일 업로드 |
| text-plain | 일반 텍스트 | 단순 텍스트 메세지 |
| application/xml | xml형식의 데이터 | 레거시 시스템과 연동 등 |
*
API를 설계할 때 Accept와 Conent-Type을 반드시 명시하도록 클라이언트에게 안내해야한다
잘못된 Content-Type으로 전송하면 Spring에선 415 Unsupported Media Type 오류 발생, 즉 사용자 문제
응답 본문의 포맷을 다양하게 처리하고 싶을 경우, @RequestMapping에서 produces 속성을 활용해라
Swagger??? 문서에서도 API의 요청/응답 포맷을 명시해주면 혼선을 줄일 수 있다고 함...
요청과 응답의 구조를 이해하는 것은 모든 API 개발의 출발점임
메서드 선택, 상태 코드의 이해, 데이터 형식 지정(Content-Type/Accept)은 실무에서 API 설계 및 디버깅 시 필수적 요소임
기본 개념을 제대로 이해해야 설계, 유지보수, 디버깅 모두 수월하다. Spring Boot의 HTTP 흐름 추상화는 도구일 뿐이다.
'Spring Boot' 카테고리의 다른 글
| Spring MVC (2) | 2025.07.02 |
|---|---|
| 서블릿(Servlet) (2) | 2025.07.01 |
| Spring AOP가 필요한 이유 (1) | 2025.07.01 |
| DTO (2) | 2025.06.26 |
| Web Server와 Web Application Server, 그리고 내장 Tomcat에 대해 (0) | 2025.06.24 |