서드 파티 HTTP 클라이언트를 사용하여 API의 REST 인터페이스에 액세스하는 커스텀 코드를 작성하는 경우 Google API가 다양한 HTTP 버전 및 구현과 호환되는 방식을 이해하는 것이 중요합니다. 대부분의 워크로드에서는 이 문서에서 설명하는 낮은 수준의 서버 통신을 자동으로 처리하는 Google의 권장 클라이언트 라이브러리를 대신 사용하세요.
통신 프로토콜 사용 (HTTP/*)
이 섹션에서는 Google API가 클라이언트와 서버 간에 통신하는 데 사용할 수 있는 지원되는 통신 프로토콜 (일반적으로 HTTP 버전)과 Google에서 권장하는 사용 방법을 설명합니다.
HTTP 시맨틱스
API 클라이언트 코드를 개발할 때는 표준 HTTP 프로토콜 시맨틱스를 따릅니다. 서버 측 프록시 또는 API 스택은 표준 HTTP 기능의 하위 집합만 지원할 수 있으며 이전 버전과의 호환성을 지원할 수도 있습니다.
API의 서버 측 구현에서 처리해야 하는 HTTP 프로토콜 시맨틱스는 서버 스택에 의해 제어됩니다. 이러한 기능이 캐싱 지원처럼 API 사양에 명시적으로 포함되어 있는 경우에는 HTTP 프로토콜 시맨틱스만 사용하세요.
HTTP 버전
클라이언트는 클라이언트 플랫폼 또는 클라이언트 측 네트워크에서 허용하거나 서버 측 프록시와 협상한 대로 HTTP/* 프로토콜을 사용할 수 있습니다. 지원되는 프로토콜에는 HTTP/1.1, HTTP/2, HTTP/3 (QUIC)이 포함됩니다. HTTP/1.0에 대한 기존 지원은 권장되지 않습니다.
일부 API 기능은 최신 버전의 HTTP 프로토콜에서만 지원될 수 있습니다. 일부는 전이중 다중화 스트리밍과 같이 HTTP/2 및 HTTP/3에서만 완전히 지정됩니다. API 사양의 일부로 이러한 기능이 필요한 경우 다양한 HTTP 버전의 제한사항을 숙지하세요. HTTP/2 서버 푸시와 같은 이전 기능은 지원 중단되었으며 최신 웹 클라이언트에서 지원되지 않습니다.
일반적으로 성능 향상, HOL(Head-of-Line) 차단 감소, 네트워크 장애에 대한 복원력 향상을 위해 HTTP/3 또는 HTTP/2를 사용하는 것이 좋습니다.
채널
채널은 Layer 4 네트워크 연결을 나타냅니다. 일반적으로 HTTP/1.1 및 HTTP/2의 경우 TCP 소켓이고 HTTP/3 (QUIC)의 경우 UDP 소켓입니다. 클라이언트 애플리케이션은 채널이 엔드 투 엔드로 관리되는 방식을 가정해서는 안 됩니다. 연결은 거의 항상 서버 프로세스를 대신하여 Google 프런트엔드(GFE) 프록시에 의해 종료되기 때문입니다.
HTTP/1.1 클라이언트: HTTP/1.1을 사용하는 경우 항상 TCP 연결을 재사용합니다(Connection: Keep-Alive). HTTP 클라이언트 라이브러리는 일반적으로 재사용을 용이하게 하기 위해 연결 풀을 관리합니다. HTTP/1.1 연결에서 HTTP 파이프라이닝을 피하세요. 지원이 제대로 되지 않으며 문제가 발생할 수 있습니다. 자세한 내용은 HTTP 및 TCP를 참고하세요.
HTTP/2 및 HTTP/3 클라이언트: 최신 클라이언트와 브라우저는 주로 HTTP/2 또는 HTTP/3을 사용합니다. 두 프로토콜 모두 다중화를 지원하므로 단일 연결을 통해 여러 요청과 응답이 동시에 전송될 수 있습니다.
- HTTP/2—원본당 단일 TCP 연결을 사용합니다.
- HTTP/3—원본당 UDP를 통한 단일 QUIC 연결을 사용합니다. QUIC는 TLS 암호화, 혼잡 제어, 연결 관리를 통합하여 연결 설정 속도 향상(0-RTT 또는 1-RTT) 및 스트림 간 TCP HOL(Head-of-Line) 차단에 대한 내성과 같은 이점을 제공합니다.
HTTP/2 및 HTTP/3을 사용하면 단일 호스트에 대한 병렬 TCP 연결 수에 대한 브라우저 제한 (예: 2~10)이 더 이상 주요 성능 문제가 되지 않습니다. 하지만 서버 (또는 GFE와 같은 프록시)는 여전히 단일 HTTP/2 또는 HTTP/3 연결 내에서 동시 스트림의 최대 수에 대한 제한을 적용할 수 있습니다. 이렇게 하면 과부하를 방지하고 공정한 리소스 사용을 보장합니다 (예: 연결당 동시 요청 또는 스트림을 100개로 제한).
HTTPS
클라이언트는 API 사양에서 지원하는 대로 HTTPS 또는 HTTP를 사용하여 API에 액세스할 수 있습니다. TLS 협상 및 TLS 버전은 클라이언트 애플리케이션에 투명합니다. Google API는 기본적으로 HTTPS 트래픽만 허용합니다.
요청 및 응답 형식
이 섹션에서는 URL로 인코딩된 데이터 사용, RESTful 작업을 위한 특정 HTTP 메서드, JSON 기반 페이로드 형식을 비롯한 API 상호작용의 구조를 설명합니다.
요청 URL
JSON-REST 매핑은 URL로 인코딩된 요청 데이터를 지원하며 HTTP 요청과 응답 본문은 application/json을 Content-Type으로 사용합니다.
HTTP 본문은 JSON 배열을 사용하여 스트리밍된 RPC 메서드를 지원하며 JSON 배열에는 JSON 메시지 또는 오류 상태 JSON 메시지가 포함될 수 있습니다.
긴 요청 URL
URL에는 실질적인 길이 제한이 있습니다. 일반적으로 기본적으로 16KB로 설정되지만 서버에 따라 다를 수 있습니다. API에서 이 길이를 초과하는 URL이 있는 GET 요청을 사용하는 경우 요청이 대상 API 서버에 도달하지 못하고 Google 프런트엔드 (GFE)에서 Your client has issued a malformed or illegal request. 오류 메시지와 함께 거부됩니다.
이 제한을 우회하려면 클라이언트 코드는 Content-Type이 application/x-www-form-urlencoded인 POST 요청을 HTTP 헤더 X-HTTP-Method-Override: GET과 함께 사용해야 합니다. 이 방법은 DELETE 요청에도 사용할 수 있습니다.
HTTP 메서드 (동사)
요청 URL이 REST 모델을 따르는 경우에는 HTTP 메서드가 API 사양의 일부로 지정됩니다. 특히 모든 API 메서드는 API 메서드가 매핑되는 특정 HTTP 동사를 기반으로 HTTP 프로토콜의 요구사항을 준수 해야 합니다. 자세한 내용은 HTTP(Hypertext Transfer Protocol) 사양 및 PATCH 메서드 RFC를 참고하세요.
안전한 메서드(HTTP GET 및 HEAD와 같은)는 검색 이외의 작업을 나타내서는 안 됩니다. 특히 HTTP GET은 안전한 메서드로 간주되어야 하며 클라이언트에서 나타나는 부작용이 있어서는 안 됩니다.
HTTP의 멱등성은 다수의 동일한 요청에서 발생하는 부작용이 단일 요청에서 발생하는 부작용과 동일하다는 것을 의미합니다. GET, PUT, DELETE는 스타일 가이드와 관련된 멱등성을 갖는 HTTP 메서드입니다. 단, 멱등성은 오직 서버 부작용과 관련하여 표현되며, 응답에 대해서는 어떤 것도 지정하지 않습니다. 특히 존재하지 않는 리소스의 DELETE는 404 (Not Found)를 반환해야 합니다.
HTTP POST 및 PATCH는 안전한 메소드도 아니고 멱등성을 갖지도 않습니다. PATCH는 RFC 5789에서 도입되었습니다.
| HTTP 동사 | 안전 | 멱등성 |
|---|---|---|
GET |
예 | 예 |
PUT |
예 | |
DELETE |
예 | |
POST |
||
PATCH |
페이로드 형식
요청이
GET이거나 "application/x-www-form-urlencoded" 본문이 있는POST인 경우를 제외하고 요청과 응답은 동일한 Content-Type을 공유해야 합니다.JSON은
application/jsonMIME 유형에서 지원됩니다. proto3과 JSON의 매핑은 JSON 매핑에서 공식적으로 지정됩니다.양식 매개변수 (
POST)는 요청 필드를 쿼리 매개변수에 매핑하는 데 동일한 REST 스타일 매핑 규칙을 따라 URL 쿼리 매개변수 (GET) 대신 사용할 수 있습니다. 지원되는Content-Type은application/x-www-form-urlencoded입니다.
스트리밍
이 섹션에서는 Google API가 클라이언트 및 서버 스트리밍을 처리하는 방법을 자세히 설명하며, 특히 반이중 통신과 전이중 통신의 제약 조건과 스트리밍된 JSON 메시지의 인코딩 요구사항을 다룹니다.
반이중과 전이중의 비교
HTTP는 TCP(HTTP/1.x) 또는 다중화 변형(SPDY, HTTP/2, QUIC) 같이 서로 다른 스트림 중심 전송을 통해 요청 또는 응답 본문을 전송할 수 있는 요청-응답 프로토콜입니다.
클라이언트 개발자의 애플리케이션은 요청 본문을 스트리밍 모드인 클라이언트 스트리밍으로 작성할 수 있습니다. 마찬가지로 애플리케이션은 응답 본문을 스트리밍 모드인 서버 스트리밍으로 사용할 수도 있습니다.
하지만 HTTP 사양은 요청 본문이 아직 대기 중일 때 서버가 오류 응답을 제외한 응답 본문을 스트리밍할 수 있는지 지정하지 않습니다. 이러한 시맨틱스는 전이중 스트리밍 이라고 알려져 있습니다. 많은 HTTP 클라이언트/서버/프록시 소프트웨어 프로그램은 HTTP/1.1에서도 전이중 스트리밍을 허용하지만 상호 운용성 문제를 방지하기 위해 HTTP 기반 Cloud API는 반이중 스트리밍으로만 제한됩니다.
기본적으로 Cloud API의 양방향 스트리밍 방식은 전이중 시맨틱스라고 가정합니다. 즉, HTTP를 사용하여 이러한 메서드를 호출하는 것은 안전하지 않습니다. 스트리밍 방식이 서버에서 적용되는 반이중 방식인 경우 API 문서는 반이중 동작을 명확하게 지정해야 합니다.
브라우저 클라이언트의 경우 표준 HTTP 시맨틱스는 브라우저 네트워크 API에 의해 추가 제한을 받습니다. 브라우저는 XHR 또는 Fetch를 사용하여 서버 스트리밍 (일반적으로 전송 수준 프레임워크를 준수)을 지원합니다. Fetch API는 whatwg 스트림을 사용합니다.
브라우저 제한이 있으므로 브라우저 지원이 필요한 Cloud API는 클라이언트 스트리밍과 전이중 스트리밍을 피하거나 브라우저 클라이언트 전용 별도의 API를 제공해야 합니다.
일반적으로 인터넷을 통한 클라이언트 스트리밍은 서버 스트리밍보다 유용하지 않습니다. 클라이언트 스트리밍을 사용하면 상태 저장 서비스가 되는 경우가 많아 부하 분산에 부정적인 영향을 미치고 시스템이 장애 또는 공격에 더 취약해지기 때문입니다. 반면 서버 스트리밍은 RTT 지연 시간이 긴 네트워크에서 지연 시간을 크게 줄일 수 있으므로 유용할 수 있습니다.
메시지 인코딩
JSON 메시지는 스트리밍할 때 JSON 메시지 배열로 인코딩됩니다. 이때 요청 또는 응답 본문은 유효한 JSON MIME 유형을 유지합니다.
클라이언트 스트리밍 인코딩 예는 다음과 같습니다.
1 <length> <message-bytes> 1 <length> <message-bytes> … EOF
서버 스트리밍 인코딩 예는 다음과 같습니다.
1 <length> <message-bytes> … 2 <length> <status-bytes> EOF
통신 프로토콜 수준 인코딩: StreamBody의 정의는 <length>일반 메시지의 경우 1~2바이트로 varint
인코딩되는 'messages' 및 'status' 필드의
태그 ID 할당에서만 중요하므로 총 인코딩
오버헤드는 메시지당 2~3바이트입니다.
선택 사항인 패딩 필드는 base64 인코딩 스트림을 지원하는 데 필요합니다.
message StreamBody {
repeated bytes message = 1;
google.rpc.Status status = 2;
repeated bytes padding = 15; // max one-byte tag-id: xxx01111
}
오류 메시지는 일반 메시지와 동일한 형식에 따라 JSON 또는 protobuf 배열의 마지막 요소로 첨부되어야 합니다.
상태 관리
절반 종료 동작은 클라이언트 또는 서버가 본문이 완성되었다는 사실을 서로 반대쪽에 알리기 위해 사용하는 모든 HTTP 버전에 알기 쉽게 정의되어 있습니다.
특히 응답을 기다리고 있을 때도 클라이언트 코드를 자유롭게 사용하여 요청을 완성할 수 있습니다. 마찬가지로 클라이언트는 요청 본문이 서버에 계속 작성되는 동안 완료된 응답을 볼 수 있습니다. HTTP 표준에 따라 클라이언트는 예상치 못한 방식으로 응답이 완성되었을 때 일반적으로 오류 상태와 함께 요청을 취소하거나 완성할 수 있습니다. 즉, 정상적인 조건에서는 클라이언트가 여전히 요청을 보내고 있을 때 서버가 응답을 완료해서는 안 됩니다.
해지
클라이언트는 해지 기능이 지원되어 요청 또는 응답이 대기 중일 때 요청을 해지할 수 있습니다.
HTTP/1.* 클라이언트에는 안정적인 해지 지원이 없습니다. 클라이언트는 요청 또는 응답 트랜잭션을 해지하지 않고 요청이 완료된 후 TCP 연결을 자유롭게 닫을 수 있기 때문입니다. HTTP/1.1에서 TCP FIN은 연결이 연결 유지로 표시된 경우에도 해지로 해석해서는 안 됩니다 (Connection: Keep-Alive).
하지만 클라이언트가 TCP 연결을 종료한 이후에 서버가 데이터를 클라이언트에 작성하려고 하면 RST가 생성되어 해지 기능을 트리거할 수 있습니다.
스트리밍이 아닌 API에서도 해지는 문제가 될 수 있습니다. 특히 응답에 긴 폴링이 포함되어 있어 연결이 장기간 유휴 상태로 유지될 수 있는 경우에 해당합니다.
명시적인 해지 기능은 SPDY, HTTP/2 및 QUIC에서, 특히 종료 메시지와 함께 지원됩니다.
연결 유지
연결 유지 기능이 지원되어 클라이언트 또는 서버가 패킷 손실 또는 네트워크 장애가 발생하는 이벤트에서도 잘못된 피어를 찾아낼 수 있습니다.
HTTP/1.1에서는 연결 유지 기능이 지원되지 않습니다. TCP 연결 유지가 가능하지 않기 때문입니다.
QUIC 또는 HTTP/2는 브라우저를 비롯한 애플리케이션에서 연결 유지 지원을 구현하기 위한 특수 제어 메시지를 제공합니다.
하지만 안정적인 연결 유지와 장애 감지를 위해서는 서버 측 지원과 함께 클라이언트 라이브러리가 필요할 수 있습니다. 인터넷을 통해 스트리밍을 장시간 지속할 때 기본적인 HTTP에만 의존하여 통신 프로토콜을 이용할 경우 오류가 자주 발생하기 때문입니다.
흐름 관리
흐름 관리 지원을 사용하려면 클라이언트가 전송 수준 흐름 관리 이벤트를 클라이언트 애플리케이션에 전파해야 합니다. 실제 메커니즘은 클라이언트 애플리케이션이 사용하는 HTTP 클라이언트 API의 스타일에 따라 달라집니다. 예를 들어 클라이언트 또는 서버가 과부하되지 않도록 하려면 애플리케이션이 흐름 관리 이벤트를 처리하고 준수할 수 있도록 차단 쓰기 및 읽기 또는 명시적 흐름 관리 지원이 있는 비차단 읽기 및 쓰기가 필요합니다.
HTTP/1.1은 TCP 흐름 제어를 이용합니다.
SPDY 및 HTTP/2에는 스트림 수준에서 자체 흐름 관리가 있으며, 단일 TCP 연결을 통해 요청이 다중화되므로 연결 수준에서 TCP 흐름 관리가 추가로 적용됩니다.
QUIC는 UDP에서 실행되므로 흐름 관리를 완전히 자체적으로 관리합니다.