POST
사용법
POST 요청은 지정된 리소스에 엔터티를 제출합니다. 서버는 그 리소스 고유의 의미에 따라 담겨 온 표현을 어떻게 처리할지 결정합니다. 특정 리소스 URI를 대상으로 하는 PUT과 달리, POST는 처리를 대상 URI가 가리키는 리소스에 위임합니다.
Content-Type 헤더는 요청 본문의 형식을 나타냅니다. HTML 폼과 API에서는 세 가지 인코딩이 흔히 쓰입니다.
application/x-www-form-urlencoded
HTML 폼의 기본 인코딩입니다. 데이터는 앰퍼샌드(&)로 구분된 키-값 쌍으로 구성되며, 키와 값은 등호(=)로 이어집니다. 영숫자가 아닌 문자는 퍼센트 인코딩을 사용합니다.
name=Alice&role=admin
multipart/form-data
각 필드는 Content-Type 헤더에 선언된 경계 문자열로 구분되는 별도의 파트를 차지합니다. 이 인코딩은 파일 업로드 같은 이진 데이터를 지원합니다. 각 파트 안의 Content-Disposition 헤더가 해당 필드의 이름을 지정합니다.
text/plain
정해진 구조가 없습니다. 서버는 자체 로직에 따라 원시 본문을 처리합니다.
POST 요청의 반복은 멱등하지 않습니다. 같은 폼을 두 번 제출하면 리소스가 두 개 생기거나 처리가 두 번 일어나며, 이는 요청을 반복해도 서버 상태가 같아지는 PUT과 다릅니다.
POST 응답은 응답에 명시적인 신선도 정보와 그에 대응하는 Content-Location 헤더가 있을 때만 캐시할 수 있습니다.
폼 제출
클라이언트가 URL 인코딩 형식으로 폼 데이터를 제출합니다. 서버는 작업을 생성하고 201 Created로 응답합니다.
요청
POST /jobs HTTP/1.1
Host: api.example.re
Content-Type: application/x-www-form-urlencoded
Content-Length: 17
name=backup&pri=2
응답
HTTP/1.1 201 Created
Location: /jobs/47
Content-Type: application/json
Content-Length: 38
{"id":47,"name":"backup","priority":2}
Multipart 파일 업로드
클라이언트가 멀티파트 인코딩으로 파일을 업로드합니다. 경계 문자열 ----Boundary가 각 파트를 구분합니다. 서버는 업로드를 받아들이고 202 Accepted를 반환합니다.
요청
POST /uploads HTTP/1.1
Host: api.example.re
Content-Type: multipart/form-data; boundary=----Boundary
Content-Length: 196
------Boundary
Content-Disposition: form-data; name="title"
Q4 Report
------Boundary
Content-Disposition: form-data; name="file"; filename="report.pdf"
Content-Type: application/pdf
<binary data>
------Boundary--
응답
HTTP/1.1 202 Accepted
Location: /uploads/91
Content-Length: 0
JSON API
클라이언트가 새 사용자를 만들기 위해 JSON 페이로드를 보냅니다. 서버는 id 필드를 포함한 생성된 리소스를 반환합니다.
요청
POST /users HTTP/1.1
Host: api.example.re
Content-Type: application/json
Content-Length: 41
{"email":"alice@example.re","role":"ops"}
응답
HTTP/1.1 201 Created
Content-Type: application/json
Content-Length: 50
{"id":112,"email":"alice@example.re","role":"ops"}
CORS
POST는 CORS 안전 목록에 포함된 메서드이지만, Content-Type이 application/x-www-form-urlencoded, multipart/form-data, text/plain인 경우에만 그렇습니다. application/json이나 그 밖의 콘텐츠 타입을 쓰는 POST는 프리플라이트 OPTIONS 요청을 유발합니다.
POST와 GET 비교
POST는 데이터를 URL이 아니라 요청 본문에 실어 보냅니다. 덕분에 매개변수가 브라우저 기록, 서버 로그, Referer 헤더에 남지 않아 민감한 데이터에 더 적합합니다.
POST 응답은 기본적으로 캐시되지 않으며 북마크할 수도 없습니다. POST는 안전하지도 멱등하지도 않으므로, 제출을 반복하면 리소스가 중복 생성되거나 처리가 여러 번 일어납니다.
POST에는 실질적인 본문 크기 제한이 없는 반면, GET은 2048자 안팎의 URL 길이 제한에 묶입니다.
SameSite=Lax 쿠키는 교차 사이트 POST 요청을 차단하지만 교차 사이트 GET은 허용합니다. 이로써 POST는 GET에는 없는 어느 정도의 기본 CSRF 보호를 갖게 됩니다.
보안
POST 데이터는 URL, 브라우저 기록, Referer 헤더에 나타나지 않습니다. 덕분에 GET에 비해 데이터가 의도치 않게 노출될 위험이 줄어듭니다.
그래도 POST는 적절한 토큰이 없으면 CSRF 공격에 취약합니다. 악성 페이지의 폼이 다른 출처로 POST 요청을 자동으로 제출합니다. SameSite=Lax 쿠키는 교차 사이트 POST의 쿠키 전송을 막아 부분적인 보호를 제공하지만, 전용 CSRF 토큰은 여전히 필요합니다.
평문 HTTP 위의 POST는 데이터를 암호화되지 않은 상태로 전송합니다. 전송 중 요청 본문을 보호하려면 HTTPS가 필요합니다.
POST와 PATCH 비교
POST는 서버가 선택한 URI에 새 리소스를 생성합니다. PATCH는 이미 알려진 URI의 기존 리소스를 수정합니다.
POST는 처리 의미를 전적으로 서버에 위임합니다. PATCH에는 적용할 구체적인 수정 내용을 기술하는 JSON Patch, JSON Merge Patch 같은 정의된 패치 형식이 있습니다.
클라이언트가 기존 리소스의 특정 필드를 갱신해야 할 때는 PATCH가 적절한 메서드입니다. POST는 새 리소스를 만들거나 서버 측 처리를 유발하는 데 씁니다.