Fetch API 사용

2023. 2. 18. 00:30IT

728x90
반응형

Fetch API 사용

Fetch API는 요청 및 응답과 같은 프로토콜 부분에 액세스하고 조작하기 위한 JavaScript 인터페이스를 제공합니다 . 또한 fetch()네트워크를 통해 리소스를 비동기적으로 가져오는 쉽고 논리적인 방법을 제공하는 글로벌 방법을 제공합니다.

이러한 종류의 기능은 이전에 XMLHttpRequest. Fetch.AI와 같은 다른 기술에서 쉽게 사용할 수 있는 더 나은 대안을 제공합니다 Service Workers. Fetch는 또한 CORS 및 HTTP 확장 과 같은 다른 HTTP 관련 개념을 정의하기 위한 단일 논리적 위치를 제공합니다 .

사양 은 다음과 같은 중요한 방식에서 fetch다릅니다 .jQuery.ajax()

  • 반환된 Promise는 응답이 HTTP 404 또는 500인 경우에도 fetch() HTTP 오류 상태에서 거부하지 않습니다 . 대신 서버가 헤더로 응답하는 즉시 Promise가 정상적으로 해결됩니다( ok응답 속성이 false로 설정된 경우). 응답이 200–299 범위에 있지 않음) 네트워크 오류가 있거나 요청 완료를 방해하는 것이 있는 경우에만 거부합니다.
  • 옵션이 , 로 설정된 상태 에서 fetch()호출되지 않는 한 :credentialsincludefetch()
    • 원본 간 요청에서 쿠키를 보내지 않습니다.
    • 원본 간 응답으로 다시 전송되는 쿠키를 설정하지 않습니다.
    • 2018년 8월부터 기본 자격 증명 정책이 same-origin으로 변경되었습니다. Firefox도 버전 61.0b13에서 수정되었습니다.)

기본 가져오기 요청은 설정이 정말 간단합니다. 다음 코드를 살펴보십시오.

fetch('http://example.com/movies.json')
  .then((response) => response.json())
  .then((data) => console.log(data));
클립 보드에 복사

여기에서는 네트워크를 통해 JSON 파일을 가져오고 콘솔에 인쇄합니다. 의 가장 간단한 사용은 fetch()하나의 인수(가져오려는 리소스의 경로)를 취하고 JSON 응답 본문을 직접 반환하지 않고 대신 개체로 해결되는 약속을 반환합니다 Response.

객체 Response는 실제 JSON 응답 본문을 직접 포함하지 않고 대신 전체 HTTP 응답을 나타냅니다. 따라서 객체에서 JSON 본문 콘텐츠를 추출하기 위해 응답 본문 텍스트를 JSON으로 구문 분석한 결과로 해결되는 두 번째 약속을 반환하는 메서드를 Response사용합니다 .json()

참고: 다른 유형의 본문 콘텐츠를 추출하는 유사한 방법은 본문 섹션을 참조하십시오 .

가져오기 요청은 검색하는 리소스의 지시가 아닌 콘텐츠 보안 정책connect-src 의 지시 에 의해 제어됩니다 .

요청 옵션 제공

 fetch()메서드는 선택적으로 두 번째 매개 변수, init다양한 설정을 제어할 수 있는 객체를 허용할 수 있습니다.

fetch()사용 가능한 전체 옵션 및 자세한 내용은 를 참조하십시오 .

// 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
  });
클립 보드에 복사

mode: "no-cors"요청에서 제한된 헤더 집합만 허용합니다 .

  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type값이 application/x-www-form-urlencoded, multipart/form-data또는text/plain

자격 증명이 포함된 요청 보내기

브라우저가 동일 출처 및 교차 출처 호출 모두에 자격 증명이 포함된 요청을 보내도록 하려면 메소드 에 전달하는 객체 credentials: 'include'에 추가하십시오 .initfetch()

fetch('https://example.com', {
  credentials: 'include'
});
클립 보드에 복사

참고: Access-Control-Allow-Origin 는 요청에 와일드카드를 사용할 수 없습니다 credentials: 'include'. 이 경우 정확한 출처를 제공해야 합니다. CORS 차단 해제 확장 프로그램을 사용하는 경우에도 요청은 계속 실패합니다.

참고: 브라우저는 이 설정에 관계없이 프리플라이트 요청 에서 자격 증명을 보내서는 안 됩니다 . 자세한 내용은 자격 증명이 있는 CORS 요청을 참조하세요 .

요청 URL이 호출 스크립트와 동일한 출처에 있는 경우에만 자격 증명을 보내려면 credentials: 'same-origin'.

// The calling script is on the origin 'https://example.com'

fetch('https://example.com', {
  credentials: 'same-origin'
});
클립 보드에 복사

대신 브라우저가 요청에 자격 증명을 포함하지 않도록 하려면 credentials: 'omit'.

fetch('https://example.com', {
  credentials: 'omit'
})
클립 보드에 복사

JSON 데이터 업로드

fetch()POST JSON 인코딩 데이터에 사용합니다 .

const data = { username: 'example' };

fetch('https://example.com/profile', {
  method: 'POST', // or 'PUT'
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(data),
})
  .then((response) => response.json())
  .then((data) => {
    console.log('Success:', data);
  })
  .catch((error) => {
    console.error('Error:', error);
  });
클립 보드에 복사

파일 업로드

파일은 HTML <input type="file" />입력 요소를 사용하여 업로드할 수 FormData()있으며 fetch().

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);
  });
클립 보드에 복사

여러 파일 업로드

파일은 HTML <input type="file" multiple />입력 요소를 사용하여 업로드할 수 FormData()있으며 fetch().

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

formData.append('title', 'My Vegas Vacation');
let i = 0;
for (const photo of photos.files) {
  formData.append(`photos_${i}`, photo);
  i++;
}

fetch('https://example.com/posts', {
  method: 'POST',
  body: formData,
})
  .then((response) => response.json())
  .then((result) => {
    console.log('Success:', result);
  })
  .catch((error) => {
    console.error('Error:', error);
  });
클립 보드에 복사

텍스트 파일을 한 줄씩 처리

응답에서 읽은 청크는 줄 경계에서 깔끔하게 끊어지지 않으며 문자열이 아닌 Uint8Array입니다. 텍스트 파일을 가져와 한 줄씩 처리하려는 경우 이러한 복잡한 문제를 처리하는 것은 사용자에게 달려 있습니다. 다음 예제는 라인 반복자를 생성하여 이를 수행하는 한 가지 방법을 보여줍니다(단순화를 위해 텍스트가 UTF-8이라고 가정하고 페치 오류를 처리하지 않음).

async function* makeTextFileLineIterator(fileURL) {
  const utf8Decoder = new TextDecoder('utf-8');
  const response = await fetch(fileURL);
  const reader = response.body.getReader();
  let { value: chunk, done: readerDone } = await reader.read();
  chunk = chunk ? utf8Decoder.decode(chunk) : '';

  const re = /\n|\r|\r\n/gm;
  let startIndex = 0;
  let result;

  while (true) {
    let result = re.exec(chunk);
    if (!result) {
      if (readerDone) break;
      let remainder = chunk.substr(startIndex);
      ({ value: chunk, done: readerDone } = await reader.read());
      chunk = remainder + (chunk ? utf8Decoder.decode(chunk) : '');
      startIndex = re.lastIndex = 0;
      continue;
    }
    yield chunk.substring(startIndex, result.index);
    startIndex = re.lastIndex;
  }

  if (startIndex < chunk.length) {
    // Last line didn't end in a newline char
    yield chunk.substr(startIndex);
  }
}

async function run() {
  for await (const line of makeTextFileLineIterator(urlOfFile)) {
    processLine(line);
  }
}

run();
클립 보드에 복사

가져오기가 성공했는지 확인

네트워크 오류가 발생하거나 CORS가 서버 측에서 잘못 구성되면 Promise는 거부됩니다. 이는 일반적으로 권한 문제 또는 이와 유사한 것을 의미합니다. 예를 들어 404는 네트워크 오류를 구성하지 않습니다 fetch(). TypeError성공에 대한 정확한 확인에는 fetch()약속이 해결되었는지 확인한 다음 Response.ok속성 값이 true인지 확인하는 것이 포함됩니다. 코드는 다음과 같습니다.

fetch('flowers.jpg')
  .then((response) => {
    if (!response.ok) {
      throw new Error('Network response was not OK');
    }
    return response.blob();
  })
  .then((myBlob) => {
    myImage.src = URL.createObjectURL(myBlob);
  })
  .catch((error) => {
    console.error('There has been a problem with your fetch operation:', error);
  });
클립 보드에 복사

자신의 요청 객체 제공

요청하려는 리소스의 경로를 호출에 전달하는 대신 생성자 fetch()를 사용하여 요청 개체를 만들고 이를 메서드 인수 Request()로 전달할 수 있습니다.fetch()

const myHeaders = new Headers();

const myRequest = new Request('flowers.jpg', {
  method: 'GET',
  headers: myHeaders,
  mode: 'cors',
  cache: 'default',
});

fetch(myRequest)
  .then((response) => response.blob())
  .then((myBlob) => {
    myImage.src = URL.createObjectURL(myBlob);
  });
클립 보드에 복사

Request()메서드와 정확히 동일한 매개 변수를 허용합니다 fetch(). 기존 요청 객체를 전달하여 복사본을 만들 수도 있습니다.

const anotherRequest = new Request(myRequest, myInit);
클립 보드에 복사

요청 및 응답 본문은 한 번만 사용할 수 있으므로 매우 유용합니다. init이와 같이 복사본을 만들면 원하는 경우 옵션을 변경하면서 다시 요청/응답을 효과적으로 사용할 수 있습니다 . 본문을 읽기 전에 복사본을 만들어야 합니다.

참고:clone() 복사본을 만드는 방법 도 있습니다 . 원본 요청 또는 응답의 본문을 이미 읽은 경우 복사본을 만드는 두 가지 방법 모두 실패하지만 복제된 응답 또는 요청의 본문을 읽어도 원본에서 읽은 것으로 표시되지는 않습니다.

헤더

인터페이스 를 사용하면 생성자 Headers를 통해 고유한 헤더 개체를 만들 수 있습니다 Headers(). 헤더 개체는 값에 대한 이름의 단순한 다중 매핑입니다.

const content = 'Hello World';
const myHeaders = new Headers();
myHeaders.append('Content-Type', 'text/plain');
myHeaders.append('Content-Length', content.length.toString());
myHeaders.append('X-Custom-Header', 'ProcessThisImmediately');
클립 보드에 복사

배열의 배열 또는 객체 리터럴을 생성자에 전달하여 동일한 결과를 얻을 수 있습니다.

const myHeaders = new Headers({
  'Content-Type': 'text/plain',
  'Content-Length': content.length.toString(),
  'X-Custom-Header': 'ProcessThisImmediately'
});
클립 보드에 복사

내용을 쿼리하고 검색할 수 있습니다.

console.log(myHeaders.has('Content-Type')); // true
console.log(myHeaders.has('Set-Cookie')); // false
myHeaders.set('Content-Type', 'text/html');
myHeaders.append('X-Custom-Header', 'AnotherValue');

console.log(myHeaders.get('Content-Length')); // 11
console.log(myHeaders.get('X-Custom-Header')); // ['ProcessThisImmediately', 'AnotherValue']

myHeaders.delete('X-Custom-Header');
console.log(myHeaders.get('X-Custom-Header')); // null
클립 보드에 복사

이러한 작업 중 일부는 에서만 유용 ServiceWorkers하지만 헤더 조작을 위한 훨씬 더 좋은 API를 제공합니다.

TypeError유효한 HTTP 헤더 이름이 아닌 헤더 이름이 사용된 경우 모든 Headers 메서드에서 오류가 발생합니다 . TypeError변경 불가능한 가드가 있는 경우 변경 작업에서 오류가 발생합니다 ( 아래 참조 ). 그렇지 않으면 조용히 실패합니다. 예를 들어:

const myResponse = Response.error();
try {
  myResponse.headers.set('Origin', 'http://mybank.com');
} catch (e) {
  console.log('Cannot pretend to be a bank!');
}
클립 보드에 복사

헤더의 좋은 사용 사례는 콘텐츠 유형을 추가로 처리하기 전에 콘텐츠 유형이 올바른지 확인하는 것입니다. 예를 들어:

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));
클립 보드에 복사

경비원

헤더는 요청으로 전송되고 응답으로 수신될 수 있으며 어떤 정보가 변경 가능하고 변경되어야 하는지에 대한 다양한 제한이 있으므로 헤더의 개체에는 가드 속성이 있습니다 . 이것은 웹에 노출되지 않지만 headers 개체에서 허용되는 변형 작업에 영향을 미칩니다.

가능한 가드 값은 다음과 같습니다.

  • none: 기본.
  • request: 요청에서 얻은 헤더 개체에 대한 보호( Request.headers).
  • request-no-cors: 로 생성된 요청에서 얻은 헤더 개체에 대한 가드입니다 .Request.mode no-cors
  • response: 응답( Response.headers)에서 얻은 헤더 개체에 대한 가드입니다.
  • immutable: 헤더 개체를 읽기 전용으로 렌더링하는 가드입니다. 주로 ServiceWorker에 사용됩니다.

참고:Content-Length 에 대한 보호된 헤더 개체에 헤더를 추가하거나 설정할 수 없습니다 response. 마찬가지로 Set-Cookie응답 헤더에 삽입하는 것도 허용되지 않습니다. ServiceWorker는 합성된 응답을 통해 쿠키를 설정할 수 없습니다.

응답 객체

위에서 본 것처럼 Promise가 해결되면 Response인스턴스가 반환됩니다 .fetch()

사용할 가장 일반적인 응답 속성은 다음과 같습니다.

  • Response.status— 응답 상태 코드를 포함하는 정수(기본값 200).
  • Response.statusText— HTTP 상태 코드 메시지에 해당하는 문자열(기본값 ""). HTTP/2는 상태 메시지를 지원하지 않습니다 .
  • Response.ok— 위에서 사용된 것처럼 상태가 200-299 범위에 있는지 확인하기 위한 속기입니다. 부울 값을 반환합니다.

JavaScript를 통해 프로그래밍 방식으로 생성할 수도 있지만 이 방법 ServiceWorkers은 메서드를 사용하여 수신된 요청에 대한 사용자 지정 응답을 제공하는 경우 에만 정말 유용합니다 respondWith().

const myBody = new Blob();

addEventListener('fetch', (event) => {
  // ServiceWorker intercepting a fetch
  event.respondWith(
    new Response(myBody, {
      headers: { 'Content-Type': 'text/plain' }
    })
  );
});
클립 보드에 복사

생성자 Response()는 응답에 대한 본문과 초기 개체( Request()수락하는 것과 유사)의 두 가지 선택적 인수를 사용합니다.

참고: 정적 메서드는 error()오류 응답을 반환합니다. 마찬가지로 redirect()지정된 URL로 리디렉션되는 응답을 반환합니다. 이들은 또한 서비스 근로자에게만 관련이 있습니다.

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

Request 인터페이스 Response는 본문을 추출하기 위해 다음 메소드를 공유합니다. 이들은 모두 실제 콘텐츠로 결국 해결되는 약속을 반환합니다.

이것은 비텍스트 데이터의 사용을 XHR보다 훨씬 쉽게 만듭니다.

요청 본문은 본문 매개변수를 전달하여 설정할 수 있습니다.

const form = new FormData(document.getElementById('login-form'));
fetch('/login', {
  method: 'POST',
  body: form
});
클립 보드에 복사

요청과 응답(및 기능 확장 fetch()) 모두 콘텐츠 유형을 지능적으로 결정하려고 시도합니다. Content-Type사전에 아무 것도 설정되지 않은 경우 요청은 자동으로 헤더를 설정합니다 .

기능 감지

Fetch API 지원은 또는 범위  Headers, 또는 가 있는지 확인하여 감지할 수 Request있습니다 . 예를 들어:Responsefetch()WindowWorker

if (window.fetch) {
  // run my fetch request here
} else {
  // do something with XMLHttpRequest?
}
728x90
반응형