fetch() 소개

fetch()를 사용하면 XMLHttpRequest(XHR)와 유사한 네트워크 요청을 할 수 있습니다. 주요 차이점은 Fetch API가 Promises를 사용한다는 점입니다. Promises에는 XMLHttpRequest API의 복잡한 콜백을 피하는 데 도움이 되는 더 간단한 API가 있습니다.

브라우저 지원

  • Chrome: 42.
  • Edge: 14.
  • Firefox: 39.
  • Safari: 10.1

소스

프로미스를 사용해 본 적이 없다면 JavaScript 프로미스 소개를 참조하세요.

다음은 XMLHttpRequest로 구현된 후 fetch로 구현된 예입니다. URL을 요청하고 응답을 가져와 JSON으로 파싱하려고 합니다.

XMLHttpRequest에는 성공 및 오류 사례와 open()send() 호출을 처리하려면 두 개의 리스너가 필요합니다. MDN 문서의 예

function reqListener () {
  const data = JSON.parse(this.responseText);
  console.log(data);
}

function reqError (err) {
  console.log('Fetch Error :-S', err);
}

const oReq = new XMLHttpRequest();
oReq.onload = reqListener;
oReq.onerror = reqError;
oReq.open('get', './api/some.json', true);
oReq.send();

가져오기

가져오기 요청은 다음과 같습니다.

fetch('./api/some.json')
  .then(response => {
    if (response.status !== 200) {
      console.log(`Looks like there was a problem. Status Code: ${response.status}`);

      return;
    }

    // Examine the text in the response
    response.json().then(function(data) {
      console.log(data);
    });
  })
  .catch(err => {
    console.log('Fetch Error :-S', err);
  });

fetch() 요청은 XHR 예시와 동일한 작업을 실행하려면 한 번만 호출하면 됩니다. 응답을 처리하려면 먼저 응답 상태가 200인지 확인한 다음 응답을 JSON으로 파싱합니다. fetch() 요청에 대한 응답은 Stream 객체입니다. 즉, json() 메서드를 호출하면 프로미스가 반환됩니다. 스트림은 비동기식으로 발생합니다.

응답 메타데이터

이전 예에서는 Response 객체의 상태와 응답을 JSON으로 파싱하는 방법을 보여줍니다. 다음은 헤더와 같이 액세스해야 할 기타 메타데이터를 처리하는 방법입니다.

fetch('users.json').then(response => {
  console.log(response.headers.get('Content-Type'));
  console.log(response.headers.get('Date'));

  console.log(response.status);
  console.log(response.statusText);
  console.log(response.type);
  console.log(response.url);
});

응답 유형

가져오기 요청을 실행하면 응답에 response.type('basic', 'cors' 또는 'opaque')가 제공됩니다. 이러한 types는 리소스의 출처를 나타내며 이를 사용하여 응답 객체를 처리하는 방법을 결정할 수 있습니다.

브라우저가 동일한 출처의 리소스를 요청하면 응답에는 응답에서 볼 수 있는 항목에 제한이 있는 basic 유형이 포함됩니다.

다른 출처의 리소스에 대한 요청이 이루어지고 해당 출처에서 CORs 헤더를 반환하면 유형은 cors입니다. cors 응답은 basic 응답과 유사하지만 볼 수 있는 헤더를 Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma로 제한합니다.

opaque 응답은 CORS 헤더를 반환하지 않는 다른 출처에서 가져옵니다. 불투명한 응답을 사용하면 반환된 데이터를 읽거나 요청 상태를 볼 수 없으므로 요청이 성공했는지 확인할 수 없습니다.

특정 요청 유형만 확인되도록 가져오기 요청 모드를 정의할 수 있습니다. 설정할 수 있는 모드는 다음과 같습니다.

  • same-origin는 출처가 동일한 애셋에 대한 요청만 성공하고 다른 모든 요청은 거부합니다.
  • cors는 동일한 출처 및 적절한 CORs 헤더를 반환하는 다른 출처의 애셋에 대한 요청을 허용합니다.
  • cors-with-forced-preflight는 요청하기 전에 사전 비행 확인을 실행합니다.
  • no-cors는 CORS 헤더가 없고 opaque 응답을 반환하는 다른 출처에 요청을 보내기 위한 것이지만, 앞서 언급한 대로 현재는 window 전역 범위에서 불가능합니다.

모드를 정의하려면 fetch 요청에서 옵션 객체를 두 번째 매개변수로 추가하고 해당 객체에서 모드를 정의합니다.

fetch('http://some-site.com/cors-enabled/some.json', {mode: 'cors'})
  .then(response => response.text())
  .then(text => {
    console.log('Request successful', text);
  })
  .catch(error => {
    log('Request failed', error)
  });

프로미스 체이닝

약속의 큰 장점 중 하나는 약속을 서로 연결할 수 있다는 점입니다. fetch()의 경우 가져오기 요청 간에 로직을 공유할 수 있습니다.

JSON API를 사용하는 경우 상태를 확인하고 각 응답의 JSON을 파싱해야 합니다. 약속을 반환하는 별도의 함수에서 상태와 JSON 파싱을 정의하고 가져오기 요청을 사용하여 최종 데이터와 오류 사례만 처리하여 코드를 간소화할 수 있습니다.

function status (response) {
  if (response.status >= 200 && response.status < 300) {
    return Promise.resolve(response)
  } else {
    return Promise.reject(new Error(response.statusText))
  }
}

function json (response) {
  return response.json()
}

fetch('users.json')
  .then(status)
  .then(json)
  .then(data => {
    console.log('Request succeeded with JSON response', data);
  }).catch(error => {
    console.log('Request failed', error);
  });

이 예에서는 response.status를 확인하고 해결된 Promise를 Promise.resolve()로 반환하거나 거부된 Promise를 Promise.reject()로 반환하는 status 함수를 정의합니다. 이는 fetch() 체인에서 호출되는 첫 번째 메서드입니다.

프로미스가 결정되면 스크립트는 json() 메서드를 호출합니다. 이 메서드는 response.json() 호출에서 두 번째 프로미스를 반환하고 파싱된 JSON이 포함된 객체를 만듭니다. 파싱에 실패하면 프로미스가 거부되고 catch 문이 실행됩니다.

이 구조를 사용하면 모든 가져오기 요청에서 로직을 공유할 수 있으므로 코드를 더 쉽게 유지 관리, 읽고 테스트할 수 있습니다.

POST 요청

웹 앱이 POST 메서드로 API를 호출하고 요청 본문에 일부 매개변수를 포함해야 하는 경우가 있습니다. 이렇게 하려면 fetch() 옵션에서 methodbody 매개변수를 설정합니다.

fetch(url, {
    method: 'post',
    headers: {
      "Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
    },
    body: 'foo=bar&lorem=ipsum'
  })
  .then(json)
  .then(data => {
    console.log('Request succeeded with JSON response', data);
  })
  .catch(error => {
    console.log('Request failed', error);
  });

가져오기 요청으로 사용자 인증 정보 전송

쿠키와 같은 사용자 인증 정보로 가져오기 요청을 하려면 요청의 credentials 값을 "include"로 설정합니다.

fetch(url, {
  credentials: 'include'
})