본문 바로가기
JavaScript

Fetch API

by oncerun 2021. 10. 17.
반응형

Fetch basic concepts

Fetch는 네트워크 통신을 포함한 리소를 가지고 오기 위한 인터페이스를 제공해주는 새로운 API입니다. 

Fetch의 핵심은 인터페이스의 추상화입니다. HTTP request, response, Headers, Body의 Payload, 그리고 비동기 리소스의 Request의 초기화를 위한 global fetch 메서드가 이 대상입니다.

 

각 네트워크 통신을 위한 각각의 객체들을 추상화하여, 각각의 객체를 추상한 후 fetch 인터페이스를 통하여, ajax의 기능 제공. HTTP의 주요 컴포넌트가 자바스크립트 오브젝트로써 추상화되어 있기 때문에,  다른  API에서 이러한 기능을 사용하게 쉽게 해 줄 수 있습니다.  예를 들면 Service Worker가 Fetch를 사용하는 API의 예시입니다.

 

Fetch는 이러한 Request의 비동기적인 성질을 한번 더 감싼 Promise 베이스의 API입니다.

 

Fetch에서는 일반적인 오브젝트로 Request 와 Response가 포함되어 있습니다.  두 객체는 service worker나 Cache API와 같이 Response와 Request 객체를 다루는 API나 독자적으로 Response를 발생시키는 경우에도 사용 가능합니다.

 

Fetch API로 리소스를 취득하기 위해서는 GlobalFetch.fetch 메서드를 사용해야 합니다. 이 메서드는 Window나 

WorkerGlobalScope와 같은 인터페이스로부터 구현되었습니다. 이 말은 window 객체도 fetch()를 구현했다는 말로 window.fetch도 사용 가능하며, 전역 스코프에서 fetch로 사용이 가능하다는 이야기입니다.

 

fetch()로 불러들이는 경우, 취득할 리소스를 반드시 인수로 지정해야 합니다. fetch()로 읽어 들인 뒤 fetch()는  Promise객체를 반환합니다. 요청이 성공하든 실패하든 해당 요청 네트워크 통신에 대한 Response객체가 취득됩니다.

fetch()의 두 번째 인수로는 초기화에 사용되는 객체를 정의하고 있습니다. 앞서 살펴보았던 Request객체의 부분이나, 전 채반적인 내용을 초기화 인수로 전달할 수 있습니다.

 

성공이든 실패든 Response를 반환하며, 콜백 함수의 매개변수에 담긴 Response객체에는 콘텐츠와, 그에 대한 처리방법이 담긴 메서드들이 담겨있습니다.

 

또한 Request와 Respoinse를 직접 작성하여 사용할 수 있지만, 이러한 방법은 FetchEvent.responseWith와 같은 또 다른 API를 불러들이는 작업이 수행되어야 하므로 필요하지 않다면 굳이 작성하지 않는 편이 좋습니다.

 

Fetch()

 

fetch() method는 네트워크에서 리소스를 가져는 프로세스를 시작하여,  응답이 완료되면 resovle를 호출해 Promise를 이행합니다. 

이렇게 반환된 Promise는 HTTP errors에 reject를 호출하지 않고, 단지 network errors에만 reject를 호출합니다. 그렇기 때문에 catch or then에서 response객체의 ok 혹은 status를 통해 상태 값마다 처리를 해주는 오류처리 코드가 필요합니다.

 

fetch() 메서드의 첫 번째 인자인 resouce에는 다음과 같은 리소스를 정의합니다.

 

  • 가져오려는 리소스의 URL을 제공하는 문자열 
  • Request 객체

fetch()메소드의 두 번째 인자에는 요청에 적용할 사용자 정의 설정이 포함된 개체입니다.

여러 옵션들이 존재하며, 몇 개를 나열하면 다음과 같습니다.

 

method, headers객체 혹은 객체 리터럴 내에 포함된 요청에 추가하려는 모든 헤더 속성, 

 

Forbidden header name

헤더를 사용자 정의할 때 금지된 헤더 속성들이 존재합니다.  사용자 에이전트인 브라우저가 헤더에 대한 모든 권한을 보유하므로 이러한 헤더를 수정하는 것은 금지되어있습니다.

 

 

  • Accept-Charset
  • Accept-Encoding
  • Access-Control-Request-Headers
  • Access-Control-Request-Method
  • Connection
  • Content-Length
  • Cookie
  • Cookie2
  • Date
  • DNT
  • Expect
  • Feature-Policy
  • Host
  • Keep-Alive
  • Origin
  • Proxy-
  • Sec-
  • Referer
  • TE
  • Trailer
  • Transfer-Encoding
  • Upgrade
  • Via

 

이러한 금지된 헤더의 이름들은 서버상에서 처리되는 속성 값들이거나, 브라우저에서 관리하는 것들이기 때문에 임의로 수정할 수 없습니다.

 

Fetch interface

 

GlobalFetch : 리소를 취득하기 위한 fetch() 메서드 정의

 

Headers : request, response에  대한 헤더 객체

 

Request : 리소스에 대한 요청 객체

 

Response : 요청에 대한 응답 객체

 

 

 

Fetch Example

// Example POST method implementation:
async function postData(url = '', data = {}) {
  // Default options are marked with *
  const response = await fetch(url, {
    method: 'POST', // *GET, POST, PUT, DELETE, etc.
    mode: 'cors', // no-cors, *cors, same-origin
    cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
    credentials: 'same-origin', // include, *same-origin, omit
    headers: {
      'Content-Type': 'application/json'
      // 'Content-Type': 'application/x-www-form-urlencoded',
    },
    redirect: 'follow', // manual, *follow, error
    referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
    body: JSON.stringify(data) // body data type must match "Content-Type" header
  });
  return response.json(); // parses JSON response into native JavaScript objects
}

postData('https://example.com/answer', { answer: 42 })
  .then(data => {
    console.log(data); // JSON data parsed by `data.json()` call
  });

 

실제로 우리가 ajax를 라이브러리를 통해 사용할 때 요청을 통해 데이터를 console에 찍어보면, 바로 객체로 찍힌다. 예를 들어 jquery 혹은 axios.. 들은 위 코드와 같이 return 할 때 Content-type이 application/json인 경우 json() 메서드를 통해 객체로 만든 뒤 반환해주기 때문이다.

또 큰 특징은 data라는 속성이 아닌, body라는 속성에 데이터를 담아 보낸다는 것이다. 당연히 HTTP 메서드인 head나 get요청에는 body가 없기 때문에 body속성을 사용할 수 없다.

 

Fetch API를 통해 파일을 업로드하는 요청은 FormData() 객체를 통해 간단히 보낼 수 있다.

const formData = new FormData();
const fileField = document.querySelector('input[type="file"]');

formData.append('username', 'abc123');
formData.append('avatar', fileField.files[0]);

fetch('https://example.com/profile/avatar', {
  method: 'PUT',
  body: formData
})
.then(response => response.json())
.then(result => {
  console.log('Success:', result);
})
.catch(error => {
  console.error('Error:', error);
});

 

fetch()를 사용할 때 헤더를 사용하는 좋은 사례는 콘텐츠 유형을 추가로 처리하기 전에 올바른지 확인하는 경우이다.

 

fetch(myRequest)
  .then(response => {
     const contentType = response.headers.get('content-type');
     if (!contentType || !contentType.includes('application/json')) {
       throw new TypeError("Oops, we haven't got JSON!");
     }
     return response.json();
  })
  .then(data => {
      /* process your data further */
  })
  .catch(error => console.error(error));

 

 

Body 

 

요청과 응답 모두 본문 데이터를 포함할 수 있습니다. 본문은 다음 유형의 인스턴스입니다.

 

  • ArrayBuffer
  • ArrayBufferView
  • Blob/file
  • String
  • URLSearchParams
  • FormData

각 본문에서 Body를 추출하기 위해 선 다음의 방법이 존재합니다.

 

  • Request.arrayBuffer() / Response.arrayBuffer()
  • Request.blob() / Response.blob()
  • Request.formData() / Response.formData()
  • Request.json() / Response.json()
  • Request.text() / Response.text(
const form = new FormData(document.getElementById('login-form'));
fetch('/login', {
  method: 'POST',
  body: form
});

 

Request, Response는 Content-type을 지능적으로 결정하려고 시도합니다. 사전에 헤더가 설정되지 않은 경우의 요청도 자동으로 헤더를 설정합니다.

 

fetch가 지원되지 않는 경우 Fetch의 폴리필을 다운로드하여 사용할 수 있습니다.

반응형

'JavaScript' 카테고리의 다른 글

구조 분해 할당  (0) 2021.10.23
JS module  (0) 2021.10.23
Fetch API Response  (0) 2021.10.16
Fetch API Request  (0) 2021.10.16
Preparation before Using "Promise"  (2) 2021.10.12

댓글