Fetch는 네트워크 요청/응답에 관련된 일반적인 Request/Response Object를 제공한다. 이 말은 범용성이 좋다는 말이다. 캐시, 웹 서비스 핸들링 등 Response를 프로그래밍 언어로 조작하는 모든 것을 허용한다는 뜻이다. 또한 CORS, HTTP Origin header semantics와 같은 개념들도 정의해놨고 이걸들을 따로 수정할 수 있다.
.fetch()
메소드를 사용하면 요청과 응답을 만들 수 있다.
fetch()는 거의 모든 상황에서 ajax 통신을 가능하게 한다.
.fetch()
는 2개의 매개변수를 받는데 첫번째는 URL이고 두번째는 Option이다. URL은 필수 매개변수이다. 그리고 이 녀석은 ajax통신이 성공하든 실패하든 response로 분해할 수 있는 Promise를 리턴한다.
fetch에는 4가지의 인터페이스와 1가지의 메소드 밖에 없다.
mixin 타입이라고 한다. Request, Response 두개 모두에서 사용된다. 딱 한가지 속성을 가지고 있는데, Body.body, Body.bodyUsed 이다. Body에는 5가지의 메소드가 존재한다.
Request와 Response의 Headers instance를 생성할 수 있다.
let myHeaders = new Header();
같이 생성할 수 있다. 생성한 Header에 속성들을 추가, 제거, 조회 할 수 있다. 다음과 같은 메소드를 제공한다.
append()
, delete()
, entries()
, forEach
, get()
, has()
, key()
, values
, getAll()
var myHeaders = new Headers();
myHeaders.append('Content-Type', 'text/xml');
myHeaders.get('Content-Type') // should return 'text/xml'
var myHeaders = new Headers({
'Content-Type': 'text/xml'
});
// or, using an array of arrays:
myHeaders = new Headers([
['Content-Type', 'text/xml']
]);
myHeaders.get('Content-Type') // should return 'text/xml'
Request instance는 요청 headers의 properties를 포함한다.
const request = new Request('https://www.mozilla.org/favicon.ico');
const URL = request.url;
const method = request.method;
const credentials = request.credentials;
fetch(request)
.then(response => response.blob())
.then(blob => {
image.src = URL.createObjectURL(blob);
});
fetch()는 Promise를 리턴하는데 Promise에서 값을 추출하면 Response를 얻을 수 있다.
간단한 express 서버와 프론트의 ajax 통신을 살펴보자
/* GET home page. */
router.get('/', function (req, res, next) {
res.render('index', { title: 'Hello, Fetch!' });
});
router.get('/title/:title', (req, res, next) => {
res.json({ title: req.params.title });
})
<h1 id="title">{{{title}}}</h1>
<input id="input" type="text">
<input type="button" value="submit" onclick="submit()">
<script>
let submit = () => {
let input = document.getElementById('input');
let tatget = document.getElementById('title');
fetch('/title/' + input.value)
.then(res => res.join())
.then(json => target.innerHTML = json.title);
}
</script>
그리고 submit 버튼을 클릭하면 왼쪽에 입력값을 파라미터로 GET 통신을 진행한다. 통신에 성공하면 서버에서 body에 JSON을 담아서 반환하고 fetch는 promise를 통해 json의 값을 뽑아낸다.
fetch('/title/'+title)
.then(res => res.join())
.then(json => target.innerHTML = json.title);
아까 언급했듯이 fetch()
는 Promise를 리턴한다. 첫번째 then에서 Response의 json을 return하고 다음 then에서 json의 값을 뽑아내서 Hello,Fetch! 에 해당하는 값을 반환한다.
router.post('/title, (req, res, next) => {
res.json({title: req.body.title});
})
let submit = () => {
let input = document.getElementById('input');
let target = document.getElementById('title');
fetch('/title, {
method: 'post',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ 'title': input.value }),
})
.then(res => res.join())
.then(json => target.innerHTML = json.title)
.catch(error => console.error('Error: ', error));
}
let submit = async () => {
let input = document.getElementById('input');
let target = document.getElementById('title');
let replaceTitle = json => target.innerHTML = json.title;
let url = '/title'
let options = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({'title': input.value}),
}
try {
let response = await fetch(url, options);
let json = await response.json();
let task = await replaceTitle(json);
} catch (err) {
console.log(err);
}
}
fetch는 기본적으로 비동기로 동작하기 때문에 가끔 원하는대로 순서대로 동작하지 않을때가 있다. 그럴때 순서를 보장받기 위해서 async / await를 사용한다.
await는 async 선언이 된 함수 안에서만 사용이 가능하며 Promise값을 기다렸다가 Promise값에서 결과값을 추출해준다. 그리고 async를 선언한 함수는 반드시 Promise를 리턴한다. 이렇게 간단하게 순서를 보장받을 수 있기 때문에 디버깅, 예외처리가 용이해진다.