반응형

curl 을 사용해 로컬에 있는 파일을 업로드하기 위해서는 다음과 같이 --upload-file(-T) 옵션을 사용하면 된다.

curl --upload-file {file path}

 

그런데 위에서 전달받은 파일을 fetch API를 사용해 다른 API의 body로 전달하려고하면 해당 파일의 타입이 ReadableStream이라 실제 파일의 타입으로 내용이 전달되지 않는다.

 

ReadableStream을 원하는 타입으로 전달하기 위해선 다음과 같이 처리하면 된다.

const response = new Response(data as ReadableStream); // stream으로 Response 객체 생성
const text = await response.text();

fetch(url, {
  method: 'post',
  // stream이 javascript 파일이라면 Content-Type 헤더를 설정해주면 된다.
  // headers: {
  //   'Content-Type': 'application/javascript',
  // },
  body: text,
});

 

반응형
반응형

TL;DR(Too Long; Didn't Read). 요약.

AbortController API를 사용해 응답이 반환되지 않은 비동기 요청을 취소할 수 있다.

const abortController = new AbortController();
fetch(request, {signal: abortController.signal}) // signal을 설정한다.
  .then(doSomthing)
});
abortController.abort(); // 원할 때 호출하면, signal을 등록한 요청을 취소한다.

 

 

 

 

전형적인 웹에서는 한번 요청이 시작하면 취소하는 것이 불가했고 그럴 필요성도 별로 없었다. 요청을 취소해야할 만한 상황이 발생한다면 요청 자체를 정말 필요한 때에만 수행하도록 처리하는 방식으로 다뤄왔을 것이다. 그렇지 않을 경우 원치 않는 응답에 대한 결과 처리가 부가적으로 필요했을 것이다.

 

하지만 이제는 AbortController API를 활용하여 응답이 반환되지 않은 요청을 취소할 수 있다.

 

과도한 새로운 정보 요청은 클라이언트(렌더링)와 서버(응답)에 부하를 주며 상용 서비스에서는 보통 비용으로도 이어진다. 따라서 필요한 시점에 요청할 수 있도록 처리가 필요하다.

중요한 점.

AbortController API는 클라이언트 API이므로, 요청을 취소한다고해도 이미 전송된 요청은 서버가 그대로 받는다. 브라우저가 자신이 전송한 요청의 응답에 대한 핸들링을 취소한다 정도로 이해하면 좋을 것 같다.

(이제와 생각해보니, 이미 서버로 날아간 요청을 어떻게 취소할 수 있다고 생각했었는지...)

 

지도를 포함하는 페이지가 있고, 지도를 이동할 때마다 화면에 나타나는 영역에 해당하는 새로운 정보를 서버로 요청하는 기능을 구현하였다고 가정해보자.

지도의 이동(move)이 발생할 때마다 새로운 정보를 요청한다면 셀 수 없이 많은 수의 요청이 발생할 것이고, 그에 따라 필요한 처리도 늘어날 것이다. 그래서 보통은 지도의 이동이 끝났을 때(moveend) 새로운 정보를 요청하는 방식을 사용한다.

하지만 원하는 영역이 나타날 때 까지 빠르게 연속해서 지도를 이동한다면, 응답이 오기전에 새로운 요청을 계속해서 생성하게 되고 응답이 오지 않은 과거의 요청은 그 의미를 잃게 된다.

 

이 경우, 각 요청에 대해 다음과 같이 AbortController를 생성하고 그 signal을 요청하는 fetch에게 넘겨주자.

map.on("moveend", (e) => {
  const abortController = new AbortController();
  fetch(request, {signal: abortController.signal})
      .then(doSomthing)
});

그 다음, 취소가 필요할 때 abortController의 abort 메소드를 호출하면된다.

let isPending = false;
let abortController;

map.on("moveend", (e) => {
  if (isPending) { // 요청이 pending 상태일 때 취소
	abortController.abort();
  }

  abortController = new AbortController();
  isPending = true;

  fetch(request, {signal: abortController.signal})
      .then((res) => {
        doSomething
      })
      .finally(() => {
      	isPending = false;
      });
});

 

자세한 내용은 MDN을 참조하자.

https://developer.mozilla.org/ko/docs/Web/API/AbortController/abort

 

AbortController.abort()

AbortController 인터페이스의 abort() 메소드는 DOM 요청(Fetch 요청과 같은)이 완료되기 전에 취소한다. 이를 통해 fetch 요청, 모든 응답 Body 소비, 스트림을 취소할 수 있다.

developer.mozilla.org

반응형

+ Recent posts