요청 취소의 경계 — 전송이 끝났으면 서버는 받는다

HTTP 요청 취소는 클라이언트에서만 일어난다.1 이미 보낸 바이트를 회수하지도, 서버가 하고 있는 일을 멈추지도 못한다.

갈리는 건 딱 하나 — 취소한 순간에 요청 전송이 이미 끝나 있었나. 끝나 있었다면 서버는 그걸 받았고, 받았으면 처리한다. 취소는 그 처리를 못 막는다.

  • reject된 promise와 “서버가 다 처리했다”는 동시에 참일 수 있다. 전송이 끝난 뒤부터 응답이 오기 전까지가 그 구간이다. 취소했다고 서버에서 아무 일도 없었던 게 아니다.
  • 절약되는 건 클라이언트 쪽뿐 — 응답을 받아 처리하는 비용. 도달했다면 서버 작업은 그대로 수행된다.
  • 네트워크 속도가 결과를 뒤집는다. abort() 를 부르는 시각이 같아도, 네트워크가 느려 전송이 그 시각을 넘겨 끝나면 “서버에 도달함”이 참에서 거짓으로 바뀐다.

요청은 네 구간을 지난다. 취소가 어느 구간에서 걸리느냐로 결과가 달라진다.

구간 어디 여기서 취소하면
send 클라이언트 요청이 다 전송되지 않는다 — 서버는 아무것도 못 받는다
in-flight 네트워크 이미 다 보냈다. 서버는 받는다
processing 서버 서버가 처리 중이고 멈출 방법이 없다
resp 네트워크 → 클라이언트 응답이 오는 중이다. 클라이언트가 안 읽을 뿐

구간 사이 경계는 셋인데 결과를 가르는 건 첫 번째 하나다 — sendin-flight 사이, 전송이 끝나는 순간. 그 뒤로는 어디서 취소하든 서버 입장에선 똑같다.

곁가지 — 라이브러리가 내부에서 만들고 돌려주지 않는 AbortController 는 밖에서 부를 수 없다. 노출된 signal 을 받는 요청만 취소가 닿는다.

Footnotes

  1. Fetch 표준의 abort 알고리즘은 controller 상태를 aborted로 바꾸고 이유를 기록할 뿐, 서버로 무엇을 보내라고 정하지 않는다. 연결을 닫거나 응답 읽기를 멈추는 건 구현 재량이다. (Fetch Standard — abort a fetch)

출처

#572raw