1. 라이브러리
  2. HTTP와 웹
  3. HTTP 메서드

업데이트됨 1개월 전

URL을 입력하고 Enter를 누르는 순간, 당신은 질문을 던지는 겁니다. GET 요청은 그게 전부입니다—서버를 향해 던지는 질문, 무언가를 보여달라는 요청. 서버가 답하고, 당신이 답을 받고, 아무것도 바뀌지 않습니다.

이 단순함에서 GET의 힘이 나옵니다.

아무것도 바꾸지 않는 질문

GET 요청은 리소스를 가져옵니다. 생성하거나 수정하거나 삭제하지 않습니다—오직 읽을 뿐입니다.

GET /api/users/123 HTTP/1.1
Host: example.com
Accept: application/json

서버는 다음과 같이 답합니다:

HTTP/1.1 200 OK
Content-Type: application/json

{"id": 123, "name": "Alice Johnson", "email": "alice@example.com"}

이 읽기 전용 특성에는 이름이 있습니다: GET은 안전합니다. 안전한 메서드는 서버의 어떤 것도 변경하지 않겠다고 약속합니다. 그냥 들여다보는 것입니다.

GET은 멱등적이기도 합니다—같은 질문을 열 번 해도 열 번 같은 답을 받습니다. 아무것도 누적되지 않습니다. 아무것도 변하지 않습니다.

이 두 특성이 이론처럼 들릴 수 있지만, 웹을 빠르게 만드는 모든 것을 가능하게 합니다.

안전성과 멱등성이 중요한 이유

GET 요청이 안전하기 때문에, 브라우저는 당신이 클릭할 수도 있는 링크를 미리 불러올 수 있습니다. 백그라운드에서 페이지를 미리 로드할 수 있습니다. GET 요청이 실수로 돈을 이체하거나 파일을 삭제하지 않는다는 걸 알기 때문에, 허락 없이도 이런 작업을 할 수 있습니다.

GET 요청이 멱등적이기 때문에, 인터넷은 실패한 요청을 자동으로 재시도할 수 있습니다. 요청 도중 연결이 끊어지면, 브라우저가 조용히 다시 시도합니다. 프록시는 응답을 캐시하여 수천 명의 사용자에게 제공할 수 있습니다. CDN은 콘텐츠를 전 세계에 배포할 수 있습니다.

인터넷의 캐싱 인프라 전체가 이 약속에 달려 있습니다: GET 요청은 질문이고, 질문은 아무것도 바꾸지 않습니다.

쿼리 파라미터로 질문 다듬기

URL 경로는 무엇을 묻는지를 나타냅니다. 쿼리 파라미터는 질문을 더 구체적으로 만들어 줍니다:

GET /api/users?role=admin&status=active&page=2 HTTP/1.1

이것은 이렇게 묻는 겁니다: "활성 상태인 관리자 사용자의 두 번째 페이지를 보여주세요."

쿼리 파라미터는 필터링(status=active), 정렬(sort=created_at), 페이지네이션(page=2&limit=50), 검색(q=javascript)에 쓰입니다. URL에 그대로 드러나기 때문에 북마크와 공유에는 안성맞춤이지만—민감한 정보에는 위험합니다.

URL은 브라우저 기록에 남습니다. 서버 로그에 기록됩니다. 리퍼러 헤더를 통해 외부로 유출됩니다. 비밀번호, API 키, 신용카드 번호는 절대 쿼리 파라미터에 넣지 마세요.

길이 제한도 있습니다. 대부분의 브라우저는 URL을 약 2,000~8,000자로 제한합니다. 그보다 많은 데이터를 보내야 한다면 다른 메서드를 써야 합니다.

캐싱: 그 보상

GET 요청은 예측 가능하기 때문에, 서버는 클라이언트에게 답을 얼마나 오래 기억해도 되는지 정확히 알려줄 수 있습니다:

Cache-Control: max-age=3600

이것은 이렇게 말하는 겁니다: "한 시간 동안은 다시 물어보지 않아도 이 응답을 재사용할 수 있습니다."

변경될 수 있는 리소스의 경우, 서버는 특정 버전의 고유한 지문인 ETag를 사용할 수 있습니다:

ETag: "abc123"

다음에 그 리소스를 요청할 때, 이렇게 물어볼 수 있습니다: "abc123 버전 이후로 변경되었나요?" 변경되지 않았다면, 서버는 304 Not Modified로 응답합니다—본문 없음, 최소한의 대역폭, 모든 것이 더 빠릅니다.

이미지나 스타일시트 같은 정적 자산은 몇 달 동안 캐시될 수 있습니다. API 응답은 몇 초에서 몇 분 동안 캐시될 수 있습니다. 전략은 달라도 원리는 같습니다: GET 요청은 그냥 질문이기 때문에 기억될 수 있습니다.

GET이 위험해지는 순간

약속을 어기면 예상치 못한 방식으로 문제가 생깁니다.

프리페치 재앙: 개발자가 /delete-account?user=123 같은 링크를 만들었는데, 클릭하면 계정이 실제로 삭제됩니다. 이메일 클라이언트가 로딩 속도를 높이려고 링크를 미리 불러옵니다. 사용자가 이메일을 열기도 전에 계정이 사라집니다. 가상의 이야기가 아닙니다—실제로 일어난 일입니다.

유출된 비밀: API 키를 편의상 쿼리 파라미터에 넣었습니다. 서버 로그에 남고, 리퍼러 헤더를 통해 검색 엔진에 색인되고, 결국 보안 침해 보고서에 올라옵니다.

이중 청구: 결제 확인에 GET을 사용합니다. "그냥 영수증을 보여주는 거니까"라는 이유로. 불안정한 연결이 브라우저를 재시도하게 만들고, 고객은 두 번 청구됩니다.

규칙은 단순합니다: 작업이 무언가를 변경한다면—레코드를 생성하거나, 결제를 처리하거나, 이메일을 보내거나, 카운터를 증가시키거나—GET이 되어서는 안 됩니다. POST, PUT, PATCH, 또는 DELETE를 사용하세요.

약속

GET은 질문입니다. 부수 효과 없이 데이터를 가져옵니다. 이 약속이 캐싱, 프리페치, 자동 재시도, 그리고 웹 전체의 성능 인프라를 가능하게 합니다.

약속을 지키면 속도와 안정성을 공짜로 얻습니다. 어기면 브라우저가 사용자의 계정을 삭제할 수도 있습니다.

GET 요청에 관한 자주 묻는 질문

브라우저가 GET 요청은 프리페치하지만 POST 요청은 그렇게 하지 않는 이유가 무엇인가요?

GET이 아무것도 변경하지 않겠다고 약속하기 때문입니다. 브라우저는 당신이 클릭할 수도 있는 페이지를 안전하게 요청할 수 있습니다. 요청 자체가 아무런 결과를 낳지 않으니까요—그냥 질문을 던지는 것입니다. POST, PUT, DELETE는 데이터를 생성하거나 수정하거나 삭제할 수 있기 때문에, 사용자가 명시적으로 행동하지 않는 한 브라우저는 절대 이런 요청을 보내지 않습니다.

GET 요청이 너무 길면 어떻게 되나요?

서버가 414 URI Too Long 오류로 거부할 가능성이 높습니다. 서버와 브라우저마다 제한이 다르지만, 2,000자 미만을 유지하는 것이 안전합니다. 더 많은 데이터를 보내야 한다면, URL 대신 요청 본문에 데이터를 담아 POST를 사용하세요.

검색 폼에 GET을 사용할 수 있나요?

네—검색은 GET에 딱 맞는 사용 사례입니다. 검색어가 쿼리 파라미터에 담기기 때문에, 사용자는 검색 결과를 북마크하거나 특정 결과로 가는 링크를 공유하거나, 브라우저 기록을 통해 이전 검색으로 돌아갈 수 있습니다. Google 검색 결과가 GET 요청인 것도 바로 이 때문입니다.

동적 데이터를 반환하는 GET 요청에서 캐싱을 방지하려면 어떻게 해야 하나요?

Cache-Control 헤더를 no-store 또는 no-cache로 설정하세요. no-store는 캐싱 자체를 막고, no-cache는 캐시를 허용하되 사용 전에 반드시 재검증하도록 합니다. 실시간 주가처럼 매우 동적인 데이터라면, no-store를 써서 모든 요청이 서버에 직접 전달되도록 하세요.

이 페이지가 도움이 되었나요?

😔
🤨
😃