하나의 웹페이지를 구성하기 위해서는 보통 프론트엔드 - 백엔드 - DB 가 갖춰져야한다.
사용자가 웹페이지를 이용하면서 어떤 데이터를 저장하려하거나, 데이터를 읽을려면
프론트엔드에서 특정 행동을 취하고(버튼 클릭등..) -> 백엔드에서 관련 로직을 실행하고 -> DB에서 데이터를 저장하거나 읽는다.
여기서 프론트엔드와 백엔드의 통신에 HTTP가 활용된다.
이 글에서 알아볼 것
- HTTP 통신의 이론
- JSON
- XMLHttpRequest vs fetch() vs axios
1. HTTP 통신의 이론
위에서 언급했듯이, HTTP 통신은 프론트와 백엔드의 의사소통에 홯용된다.
이를 자세히 알아보자
- 브라우저 - 프론트 - 백엔드 소통
- 사용자 화면에 HTML 문서를 렌더링하는 작업은 흔히 프론트엔드라 불리는 기술없이, 오직 백엔드 기술만으로도 가능하다.…SSR
- 하지만, 불필요한 새로고침을 방지하는등의 더 나은 사용자 경험을 제공하기 위해서 프론트엔드를 활용할 수 있다….CSR
- 여기서 말하는 불필요한 새로고침이란, 만약 서버와 브라우저가 바로 소통하면 서버가 항상 새로운 html 페이지를 반환해야함에 따라 재렌더링(새로고침)이 발생한다
- 따라서, 백엔드 <-> 프론트엔드 <-> 브라우저와의 소통이 이루어지면서 더욱 다양한 작업을 수행할 수 있게된다
- 여기서 말하는 백엔드는 보통 API(Application Programming Interface)를 말하는데, 여기서는 어떤 요청을 어떤 url에 받느냐에 따라 하는 기능이 달라지고, 이를 결정하는 것이 백엔드 개발자들이다.
- 여기서 중요한 점은, 보안 상의 이유로 절대!!! 프론트를 바로 DB에 연결하면 안된다.
그러면 위의 작업을 수행하는데 HTTP가 활용된다 하였는데, 어떻게 활용될까?
- 예를들어 사용자가 웹사이트에서 버튼을 클릭하여 양식을 제출한다고 가정해보자
- 그러면 클라이언트 → 서버로 HTTP 요청을 보낸다
- *참고: 이러한 의사소통을 위해서는 URL이 존재해야하는데,
- URL은 도메인 + 경로(path)로 이루어져있다.
- ex) joseph0926.tistory.com/post에서 joseph0926.tistory.com는 도메인이고, /post는 경로다
- *참고: 이러한 의사소통을 위해서는 URL이 존재해야하는데,
- HTTP 요청에는 HTTP 메서드 중 하나가 포함되어있어, 이 요청을 통해 어떠한 작업을 수행하고 싶은지 알려준다.
- HTTP 메서드란?
- GET
- 일반적으로 데이터를 얻기 위해 사용
- POST
- 서버에서 데이터 생성등에 사용
- PATCH, PUT
- 데이터를 업데이트하는데 사용 (PATCH → 업데이트, PUT → 오버라이드)
- DELETE
- 데이터를 삭제하는데 사용
- GET
- HTTP 메서드란?
- 또한, HTTP 요청에는 Header와 Body도 포함되는데,
- Header
- HTTP 요청에 연결할 수 있는 추가 메타데이터
- Body
- 어떤 데이터를 보낼때 Body를 통해 보낸다
- 보통 데이터 형식은 JSON (FormData 형식이나, Binary 형식도 존재한다)
- Header
- 그러면 클라이언트 → 서버로 HTTP 요청을 보낸다
이렇게 HTTP 요청을 통해 클라이언트에서 서버로 통신을 할 수 있다는 사실과, HTTP 요청에 뭐가 포함되는지 알아보았다
그러면 이러한 HTTP 요청은 어떻게 보낼까?
2. JSON
그전에 알고가야할 중요한 개념이 존재한다.
바로 "JSON" 이다.
- JSON이란?
- JavaScript Object Notation의 약자로 데이터를 저장하거나 전송할 때 많이 사용되는 데이터 형식이다.
- JSON은 {"name": "messi"} 이런 형식으로 생겼는데, 자바스크립트 객체와 매우 유사해보인다.
- 하지만 JSON은 데이터만 저장 가능하고, 메서드는 존재하지 않는다
- 또한, 프로퍼티 이름은 “”로 감싸줘야한다
- 이러한 JSON은 HTTP 통신시 데이터 전달에 가장 많이 사용되는 형식이다.
- 다만, JSON 데이터는 자바스크립트에서 바로 사용할수는 없다.
- JSON.stringify()
- 자바스크립트 코드 → JSON 데이터
- JSON.parse()
- 자바스크립트 코드 ← JSON 데이터
- JSON.stringify()
3. XMLHttpRequest vs fetch() vs axios
자바스크립트에는 HTTP 요청을 위해 내장된 기능이 두개 존재한다.. XMLHttpRequest 객체와 fetch() 메서드다.
또한 자바스크립트의 작업을 도와주는 라이브러리가 존재하는데,
그중 HTTP 요청과 관련된 axios라는 라이브러리가 존재한다.
- XMLHttpRequest
- XMLHttpRequest는 자바스크립트에서 HTTP 요청을 위해 사용하는 객체로, 상당히 오래전부터 존재하였다.
- 사용법은 XMLHttpRequest 객체를 생성하고, 특정 구문, 메서드를 활용하여 요청을 보내는 것인데, 이렇게 글로만 보면 이해가 잘 안되고, 코드로 직접 확인해보자
GET
const listEl = document.querySelector(".posts");
const postTem = document.getElementById("single-post");
const xhr = new XMLHttpRequest();
// XMLHttpRequest 객체 생성
xhr.open("GET", "https://jsonplaceholder.typicode.com/posts");
// open("HTTP 메서드", "url")
xhr.responseType = "json";
// 데이터의 타입을 정해준다
xhr.onload = function () {
// const listOfPosts = JSON.parse(xhr.response);
const listOfPosts = xhr.response;
// 받아온 데이터를 상수에 저장
for (const post of listOfPosts) {
const postEl = document.importNode(postTem.content, true);
postEl.querySelector("h2").textContent = post.title.toUpperCase();
postEl.querySelector("p").textContent = post.body;
listEl.append(postEl);
}
};
// onload를 통해 데이터를 활용할수있다.
xhr.send();
// HTTP 요청을 보낸다
또한 XMLHttpRequest 은 프로미스화가 가능하다.
const sendHttpReq = (method, url) => {
const promise = new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.responseType = "json";
xhr.onload = function () {
resolve(xhr.response);
// const listOfPosts = JSON.parse(xhr.response);
};
xhr.send();
});
return promise;
};
const fetchPosts = () => {
sendHttpReq("GET", "https://jsonplaceholder.typicode.com/posts").then((responseData) => {
const listOfPosts = responseData;
for (const post of listOfPosts) {
const postEl = document.importNode(postTem.content, true);
postEl.querySelector("h2").textContent = post.title.toUpperCase();
postEl.querySelector("p").textContent = post.body;
listEl.append(postEl);
}
});
};
// then 사용
const fetchPosts = async () => {
const responseData = await sendHttpReq("GET", "https://jsonplaceholder.typicode.com/posts");
const listOfPosts = responseData;
for (const post of listOfPosts) {
const postEl = document.importNode(postTem.content, true);
postEl.querySelector("h2").textContent = post.title.toUpperCase();
postEl.querySelector("p").textContent = post.body;
listEl.append(postEl);
}
};
// async / await 사용
POST
/*
GET에서 사용했던 sendHttpReq()메서드를 수정해준다
sendHttpReq(method, url) => {} 에서 sendHttpReq(method, url, data) => {}으로
-> 왜냐하면 post라는 것에서 알수있듯 데이터를 보낼것이기 때문
xhr.send(); 에서 xhr.send(JSON.stringify(data)) 으로
-> 데이터를 그냥 보내면 안되고 JSON등의 형식으로 바꿔줘야한다
*/
const createPost = async (title, content) => {
const userId = Math.random();
const post = {
title: title,
body: content,
userId: userId,
};
sendHttpReq("POST", "https://jsonplaceholder.typicode.com/posts");
};
- fetch()
- 원래 자바스크립트는 XMLHttpRequest만을 사용하여 HTTP 요청을 해결하였지만, 최신 자바스크립트에서는 fetch() 메서드가 추가되었다.
- fetch() 메서드는 브라우저에 내장되어있고, 전역에서 사용가능하고, 프로미스 함수다
- 이것도 코드를 통해 확인해보자
GET
const sendHttpReq = (method, url, data) => {
return fetch(url).then((res) => {
//fetch() 메서드는 두개의 인자를 받는데, 하나는 url이고 다른 하나는 객체이다.
//또한, 두번째 인자인 객체에서 HTTP 메서드를 설정해줄수있는데,
//따로 명시하지 않으면 자동으로 GET이다.
return res.json();
//res는 파싱 되지 않은 스트리밍 본문이다,
//따라서 파싱된 스냅샷 본문으로 바꿔줘야하고, 그것이 res.json()이다
});
}
const fetchPosts = () => {
sendHttpReq("https://jsonplaceholder.typicode.com/posts").then((responseData) => {
const listOfPosts = responseData;
for (const post of listOfPosts) {
const postEl = document.importNode(postTem.content, true);
postEl.querySelector("h2").textContent = post.title.toUpperCase();
postEl.querySelector("p").textContent = post.body;
postEl.querySelector("li").id = post.id;
listEl.append(postEl);
}
});
};
// 이부분은 XMLHttpRequest와 동일
POST
return fetch(url, {
//앞서 말한대로 두번째 인자는 객체다,
//객체에는 여러 프로퍼티를 설정할수있는데, 보통 method, body, header를 설정한다
method: method,
body: JSON.stringify(data),
}).then((res) => {
return res.json();
});
const createPost = async (title, content) => {
const userId = Math.random();
const post = {
title: title,
body: content,
userId: userId,
};
sendHttpReq("POST", "https://jsonplaceholder.typicode.com/posts");
};
// 여긴 XMLHttpRequest와 동일
- axios
- axios는 위의 두 기능과 달리 따로 설치해줘야하는 타사 라이브러리이다.
- 또한, axios는 여러 메서드를 갖는 전역객체이며 프로미스를 사용한다
- 뒤에서 header에 대해 살펴보겠지만 axios는 header를 따로 추가할 필요가 없다
- axios의 사용법은 비교적 간단하니 글로 확인해보자
- html 파일에 <script src ="https://unpkg.com/axios/dist/axios.min.js" defer>을 추가해준다
- 물론 npm을 이용해 직접 설치하여도 괜찮다..(뒤에 글에서 다룰것)
- GET
- const res = await axios.get(url)
- POST
- const res = await axios.post(url, data)
- html 파일에 <script src ="https://unpkg.com/axios/dist/axios.min.js" defer>을 추가해준다
- res.data로 json 데이터를 읽을수있다
자바스크립트에서 HTTP 요청을 보낼 수 있는 3개의 방법을 살펴보았다.
여태까지 글에서 많이 vs를 하며 비슷한 기능들을 비교하고 선택하였고, 대부분 상황에 따라 적절하게 사용하자는 결론이 나왔었다.
하지만, 이번에는 어느정도 정답을 정할수있을것같다.
XMLHttpRequest 보다는 fetch()나 axios를 사용하자..!
XMLHttpRequest는 오래된만큼 사용법이 복잡하고,,무엇보다 프로미스화를 직접 해주어야한다.
따라서, 나는 타사 라이브러리를 설치할 경우에는 axios를 사용할 것 같고, 아니라면 fetch()를 사용할 것 같다.
*추가
위의 3가지 방법이 오류를 어떻게 다루는지 확인해보자
1. XMLHttpRequest
xhr.onload = function () {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response);
// const listOfPosts = JSON.parse(xhr.response);
} else {
reject(new Error("error!"));
}
};
// 요청 전송은 성공했으나 후에 무슨 문제가 발생했을때
xhr.onerror = () => {
reject(new Error("error!!!"));
}
// 요청 전송 자체가 실패했을때
물론 프로미스화가 되어있으면, .catch블럭이나 try-catch를 사용해도된다.
2. fetch()
- fetch()는 프로미스이므로 당연히 catch블럭을 사용할 수 있다.
- 하지만 문제점이 있는데, 1번에서 살펴본 “요청 전송은 성공했으나 후에 무슨 문제가 발생했을때”에 대한 처리가 불가능하다
- 즉, 이 방법으로는 기술적 이슈, 네트워크 이슈등만 잡을수있다
- 그럼 어떻게 처리할까? ⇒ 1번에서 했던것처럼 if-else를 사용한다
return fetch(url, {
method: method,
body: JSON.stringify(data),
headers: {
"Content-Type": "appliction/json"
}
}).then((res) => {
if (res.status >= 200 && res.status < 300) {
return res.json()
} else {
return res.json().then((errorData) => {
console.log(errorData);
throw new Error("Error!");
})
}
}).catch((err) => {
console.log(err);
throw new Error("Error");
});
3. axios
- try - catch로 처리
*HTTP 요청에서의 header
HTTP 요청에서 헤더에는 메타 데이터가 들어간다고 하였다.
3개의 방법이 각각 어떻게 헤더를 표현하는지 확인해보자
- XMLHttpRequest
- xhr.setRequestHeader("Content-Type", "appliction/json")
- 이걸 여러줄 반복해서 여러 header 데이터를 보낼수있다
- 한번 추가된 헤더는 삭제 불가능하다
- xhr.setRequestHeader("Content-Type", "appliction/json")
- fetch()
return fetch(url, {
method: method,
body: JSON.stringify(data),
headers: {
"Content-Type": "appliction/json"
}
}).then((res) => {
return res.json();
});
3. axios
헤더 필요없음...
'OLD > Javascript' 카테고리의 다른 글
[Javascript] 자바스크립트로 브라우저 저장소 이용하기 (LocalStorage, Cookies, indexedDB) (0) | 2023.02.27 |
---|---|
[Javascript] 자바스크립트 모듈 (0) | 2023.02.26 |
[Javascript] 자바스크립트 비동기(Async)_01 (sync & async 코드, 이벤트 루프, 콜백함수, async / await 키워드) (0) | 2023.02.25 |
[Javascript] 자바스크립트 Number & String (부동 소수점, BigInt, 태그된 템플릿) (0) | 2023.02.24 |
[Javascript] 자바스크립트 고급 함수 (순수 함수 & 부수 효과, 팩토리 함수, 클로저) (0) | 2023.02.23 |