(해석 또는 이해가 잘못된 부분이 있다면 댓글로 편하게 알려주세요.)
Connection management—particularly knowing when and how to close connections—is one of the practical black arts of HTTP. This issue is more subtle than many developers first realize, and little has been written on the subject.
연결을 관리하는 것, 특히 언제 어떻게 연결을 종료할지 아는 것은 HTTP의 실질적인 암흑 기술 중 하나입니다.
해당 이슈는 많은 개발자들이 처음 생각했던 것보다 더 미묘하고 이 주제에 대한 글도 거의 작성되지 않았습니다.
Any HTTP client, server, or proxy can close a TCP transport connection at any time. The connections normally are closed at the end of a message,* but during error conditions, the connection may be closed in the middle of a header line or in other strange places.
모든 HTTP 클라이언트나 서버 혹은 프록시는 TCP 전송 연결을 언제든 종료할 수 있습니다.
일반적으로 연결은 메시지가 끝날 때 종료되지만 오류가 발생하면 헤더 라인의 중간이나 다른 이상한 위치에서 종료될 수도 있습니다.
This situation is common with pipelined persistent connections. HTTP applications are free to close persistent connections after any period of time. For example, after a persistent connection has been idle for a while, a server may decide to shut it down.
이 상황은 파이프라이닝된 Persistent 연결에서 일반적으로 나타납니다.
HTTP 응용 프로그램은 일정 시간이 지나고 나면 Persistent 연결을 자유롭게 닫을 수 있습니다.
예를 들어 Persistent 연결이 잠시 동안 유휴 상태가 되면 서버는 이 연결을 종료하려고 할지도 모릅니다.
However, the server can never know for sure that the client on the other end of the line wasn’t about to send data at the same time that the “idle” connection was being shut down by the server. If this happens, the client sees a connection error in the middle of writing its request message.
하지만 서버가 비어있는 연결을 종료하려던 찰나에 반대편에 위치한 클라이언트가 메시지를 전송하려던 참이었을지도 모릅니다. 문제는 이 사실을 서버가 알지 못한다는 점입니다.
이러한 상황이 발생하면 클라이언트는 요청 메시지를 작성하던 중 연결 오류를 마주하게 됩니다.
Each HTTP response should have an accurate Content-Length header to describe the size of the response body. Some older HTTP servers omit the Content-Length header or include an erroneous length, depending on a server connection close to signify the actual end of data.
HTTP 응답은 정확한 Content-Length 헤더를 보유하여 응답 본문의 크기를 표현해야 합니다.
일부 오래된 HTTP 서버들은 데이터의 실질적인 종료를 나타내는 서버의 연결 종료에 따라 Content-Length 헤더를 생략하거나 잘못된 길이를 포함합니다.
When a client or proxy receives an HTTP response terminating in connection close, and the actual transferred entity length doesn’t match the Content-Length (or there is no Content-Length), the receiver should question the correctness of the length.
If the receiver is a caching proxy, the receiver should not cache the response (to minimize future compounding of a potential error). The proxy should forward the questionable message intact, without attempting to “correct” the Content-Length, to maintain semantic transparency.
만약 수신단이 캐싱 프록시라면, 수신단은 응답을 캐싱하지 않아야 합니다(미래에 발생할 수 있는 잠재적인 오류가 복잡해지는 것을 최소화).
프록시는 Content-Length를 수정하지 않고 의심스러운 메시지를 그대로 전송해야 합니다. 의미론적인 투명성을 유지하기 위함입니다.
Connections can close at any time, even in non-error conditions. HTTP applications have to be ready to properly handle unexpected closes. If a transport connection closes while the client is performing a transaction, the client should reopen the connection and retry one time, unless the transaction has side effects. The situation is worse for pipelined connections. The client can enqueue a large number of requests, but the origin server can close the connection, leaving numerous requests unprocessed and in need of rescheduling.
연결은 오류가 발생하지 않은 상황이라면 언제든 종료될 수 있습니다.
HTTP 응용 프로그램은 예상치못한 종료를 적절하게 처리하기 위한 준비가 필요합니다.
만약 클라이언트가 트랜잭션을 수행하던 중 전송 연결을 종료하면, 트랜잭션의 부작용이 없는 한 클라이언트는 연결을 다시 설정하고 재전송해야 합니다.
파이프라이닝된 연결에서 이 상황은 더 심각하게 발생합니다.
클라이언트가 대량의 요청을 대기열에 넣을 수 있지만, origin 서버가 연결을 종료하게 되면 처리되지 않은 많은 요청을 남기며 리스케줄링이 필요해집니다.
Side effects are important. When a connection closes after some request data was sent but before the response is returned, the client cannot be 100% sure how much of the transaction actually was invoked by the server. Some transactions, such as GETting a static HTML page, can be repeated again and again without changing anything. Other transactions, such as POSTing an order to an online book store, shouldn’t be repeated, or you may risk multiple orders.
부작용 또한 중요합니다.
일부 요청 데이터가 전송되었지만 응답이 돌아오기 전 연결이 종료되었을 때, 클라이언트는 실제로 서버에 의해 트랜잭션이 얼마나 호출되었는지 100% 확신할 수 없습니다.
정적인 HTML 페이지를 GET하는 것과 같은 일부 트랜잭션은 무언가를 변화시키지 않고 반복해서 수행될 수 있습니다.
온라인 서점에 주문을 POST하는 것과 같은 다른 트랜잭션은 반복되지 않거나 중복 주문의 위험을 감수해야 합니다.
A transaction is idempotent if it yields the same result regardless of whether it is executed once or many times. Implementors can assume the GET, HEAD, PUT, DELETE, TRACE, and OPTIONS methods share this property.* Clients shouldn’t pipeline nonidempotent requests (such as POSTs). Otherwise, a premature termination of the transport connection could lead to indeterminate results. If you want to send a nonidempotent request, you should wait for the response status for the previous request.
트랜잭션이 몇 번 실행되었는지와 관계없이 항상 동일한 결과를 내놓는다면 이 트랜잭션은 멱등성을 가진 것입니다.
구현자는 GET, HEAD, PUT, DELETE, TRACE, OPTIONS 메소드가 이러한 특성을 공유할 것이라고 가정합니다.
클라이언트는 POST와 같은 비멱등적인 요청을 파이프라이닝해서는 안 됩니다.
그렇지 않으면 전송 연결의 비정상적인 종료로 예상치못한 결과가 나올 수 있습니다.
만약 비멱등적인 요청을 보내고자 한다면, 여러분은 이전 요청에 대한 응답 상태를 기다려야 합니다.
Nonidempotent methods or sequences must not be retried automatically, although user agents may offer a human operator the choice of retrying the request. For example, most browsers will offer a dialog box when reloading a cached POST response, asking if you want to post the transaction again.
유저 에이전트가 운영자에게 요청을 재전송할 수 있는 선택권을 부여할 수는 있지만, 비멱등적인 메소드나 시퀀스는 자동으로 재전송되어서는 안 됩니다.
예를 들어, 대부분의 브라우저는 캐시된 POST 응답을 재로딩할 때 이 트랜잭션을 다시 전송할 것인지 묻는 dialog box를 제공할 것입니다.
Idempotency를 가진 요청이 이전 요청에 대한 응답을 확인하고 재전송을 해야 하는 이유가 이제야 좀 와닿습니다. 지난 포스팅에서는 그렇구나, 정도로만 이해했었는데.. 요청에 대한 응답이 돌아오지 않으면 서버가 트랜잭션을 얼마나 호출했는지를 알 수 없기 때문에, 동일한 결과를 내놓지 않는 트랜잭션의 경우에는 자동으로 재전송을 하면 안 되는 거였습니다.
그렇다면 응답이 돌아오지 않고 연결이 종료되었을 때는 어떻게 처리가 되는 걸까요. 클라이언트가 서버에게 연결을 열고 이전 요청에 대한 응답이 올 때까지 기다리는 걸까요? 연결을 열고 응답을 기다리는데도 응답이 오지 않으면 그제서야 재요청을 보낼 수 있는 걸까요? 지피티한테 저의 이런 생각을 막 얘기했는데 딱히 틀렸다고는 하지 않았습니다. 지피티를 믿을 수가 없다는 게 문제지만용...