AJAX & AXIOS

CHAENG·2024년 7월 25일
0

FrontEnd

목록 보기
6/10

서버와 통신하기 전에, 개념을 확실하게 정리하고 넘어가고싶어서 해당 개념을 정리하기로 했다. Axios를 사용했던 경험은 있지만 모르는 부분도 많은 상태에서 항상 급급하게 코드만 작성해왔던 것 같아 이번에는 꼼꼼하게 정리하고 구조를 이해해서 작성해보고자 한다.

출처 링크

https://velog.io/@bcl0206/Ajax의-개념-등장배경-장점

https://velog.io/@surim014/AJAX란-무엇인가

https://hstory0208.tistory.com/entry/비동기-통신-Ajax와-Axios의-차이점

https://velog.io/@kysung95/개발상식-Ajax와-Axios-그리고-fetch

https://inpa.tistory.com/entry/AXIOS-📚-설치-사용

https://ramincoding.tistory.com/entry/React-Axios-간단하게-사용하기


✅ Ajax

  • Asyncronous JavaScript and XML의 약자로 자바스크립트의 라이브버리 중 하나이다.
  • 자바스크립트를 통해서 서버에 데이터를 비동기 방식으로 요청하는 웹 개발 기술
    • 브라우저가 서버에게 비동기 방식으로 데이터를 요청하고, 서버가 응답한 데이터를 수신하여 웹페이지를 동적으로 갱신하는 프로그래밍 방식
    • 페이지를 새로고침 없이 페이지 일부의 데이터 변경 가능

사용자 경험 향상, 웹 애플리케이션의 성능개선에 도움

등장배경

  • Ajax 이전 웹페이지는 서버로부터 새로운 HTML을 받아 웹페이지 전체를 처음부터 다시 렌더링 하는 방식이였다.

    1. 변경할 필요가 없는 부분까지 포함된 완전한 HTML을 서버로부터 매번 다시 전송받기 때문에 불필요한 데이터 통신이 발생
    2. 이로인해 화면 전환이 일어날 때 순간적인 화면 깜빡임 현상 발생
    3. 클라이언트와 서버와의 통신이 동기 방식으로 동작하기 때문에 서버로부터 응답이 있을 떄까지 다음 처리는 블로킹됨

해당 단점을 극복하고자 Ajax의 개념 등장

Ajax 장점

  • 필요한 데이터만 서버로부터 전송받아, 불필요한 데이터 통신이 발생하지 않음
  • 비동기 방식으로 동작하므로, 서버에게 요청을 보낸 후, 블로킹 현상이 일어나지 않음
    • 따라서 웹페이지의 속도 향상, 사용자 경험 향상
  • 기존 웹에서 불가능했던 다양한 UI를 구현할 수 있음
    • ex) 사진의 제목이나 태그를 페이지의 리로드없이 수정 가능

Ajax 단점

  • 히스토리 관리가되지 않음
  • 페이지의 이동이 없는 통신으로 보안상 문제 발생 가능
  • Script로 작성되어 디버깅에 용이하지 않음
  • 동일출처정책으로 다른 도메인과는 통신이 불가함 (Cross-Domain문제)

Ajax 사용법

  • XMLHttpRequest 객체 사용
  • fetch 사용
  • jQuery 사용
  • Axios 사용 (React or Vue 환경)

✅ Axios

  • 웹 애플리케이션에서 사용하는 Ajax 기반 API 호출을 단순화하고 향상시키기 위한 JavaScript 라이브러리
  • HTTP 요청에 최적화 되어있고, 상태가 추상화 되어있는 API중 하나
  • Ajax를 사용할 때 발생할 수 있는 불편함을 보완하는 기능 제공
  • 비동기 HTTP 통신이 가능하며 return을 Promise객체로 해주기 때문에 response 데이터를 다루기 쉬움

Ajax를 효율적으로 활용할 수 있게 도와주는 라이브러리

Axios가 추가적으로 제공하는 기능

  • Axios는 Promise 기반으로, XMLHttpRequest객체를 사용할 때 보다 코드를 더 간결하게 작성할 수 있음
  • 비동기 요청을 보낼 때 발생할 수 있는 에러를 간편하게 catch 할 수 있음
  • 응답 데이터를 자동으로 JSON으로 변환해주기 때문에, parsing이나 stringify 과정이 필요없음
  • HTTP 요청이 전송되기 전이나, 서버로 부터 응답을 받기전에 데이터를 처리할 수 있는 인터셉터 기능 제공
  • 긴 응답시간이 발생할 경우, 요청을 자동으로 취소하고 에러를 반환하는 타임아웃 시간 설정 가능

Axios 장점

  • response timeout 처리 방법제공 (fetch에는 존재하지 않음)
  • Promise 객체 기반으로 다루기 편리함
  • 크로스 브라우징에 최적화 되어있어, 브라우저 호환성이 뛰어남

Axios 단점

  • 프로젝트에 별도로 추가해야하는 외부 라이브러리
  • 내장 fetch에 비해 상대적으로 크기가 큰 편임

간단하게 사용할 때는 fetch, 확장성을 고려할 경우에는 axios 사용이 더 좋음


✅ Axios 문법

axios({
  url: 'https://test/api/cafe/list/today', // 통신할 웹문서
  method: 'get', // 통신할 방식
  data: { // 인자로 보낼 데이터
    foo: 'diary'
  }
});

✅ Axios 사용법

  • 보내고자 하는 요청에 대한 설정을 config 객체에 담아서 보낸다.

config 객체 종류

  • method
    • HTTP 요청 메소드로, GET이 기본적으로 사용된다
  • url
    • 요청을 보낼 URL 주소 지정
  • params
    • URL의 쿼리 매개변수를 설정
  • headers
    • 요청 헤더, 사용자 정의 헤더 추가 가능
  • data
    • 요청 body에 보낼 데이터 설정
    • request body
      • 클라이언트가 서버로 전송하고자하는 데이터가 포함됨
      • json 형식으로 데이터를 전송하거나 form 데이터, multi part 데이터를 포함할 수 있음
  • baseURL
    • 공통적으로 사용하는 기본 URL 주소 설정
  • responseType
    • 서버에서 받을 응답 데이터 형식 지정
  • withCredentials
    • 쿠키 및 HTTP 인증 정보를 포함하도록 설정하는 옵션
  • auth
    • 요청에 대한 HTTP 기본 인증 설정, 사용자 이름 & 암호를 제공해서 인증 수행

사용예시

// GET 요청
axios({
  method: 'get',
  url: url,
  params: {
    id: 1,
    category: 'review'
  },
  headers: {
    Authorization: 'Bearer YourAccessToken'
  }
})
.then((res) => {
  console.log(res.data);
})
.catch((err) => {
  console.error(err);
});

// POST 요청
axios({
  method: 'post',
  url: url,
  data: {
    name: 'Dev',
    title: 'good review'
  }
});
  • method를 생략하고 url만 전달하게 된다면, 기본적으로 GET요청을 전송한다.

Axios 응답(response) 데이터

  • 서버에게 요청을 보내면, 서버에서 처리를 하고 다시 데이터를 클라이언트에게 응답하게 된다.
  • 이를 .then 함수인자로 받아 객체에 담겨진 데이터를 응답 데이터라고 한다.
response.data: {}, // 서버가 제공한 응답(데이터)
response.status: 200, // `status`는 서버 응답의 HTTP 상태 코드
response.statusText: 'OK',  // `statusText`는 서버 응답으로 부터의 HTTP 상태 메시지
response.headers: {},  // `headers` 서버가 응답 한 헤더는 모든 헤더 이름이 소문자로 제공
response.config: {}, // `config`는 요청에 대해 `axios`에 설정된 구성(config)
 
// `request`는 응답을 생성한 요청
// 브라우저: XMLHttpRequest 인스턴스
// Node.js: ClientRequest 인스턴스(리디렉션)
response.request: {}

✅ Axios 단축 메소드

  • GET : axios.get(url[, config])
  • POST : axios.post(url, data[, config])
  • PUT : axios.put(url, data[, config])
  • DELETE : axios.delete(url[, config])
  • etc : axios.request(config) / axios.head(url[, config]) / axios.options(url[, config]) / axios.create([config])

GET 요청

  • 웹 애플리케이션에서 서버로 데이터를 요청할 때 사용되는 메서드
    • 단순 데이터 (페이지 요청, 지정된 요청) 요청을 수행할 경우
    • 파라미터 데이터를 포함시키는 경우 (사용자 번호에 따른 조회)
// user에게 할당된 id 값과 함께 요청을 합니다.
axios.get('/user?ID=12345')
  .then(function (response) {
    // 성공했을 때
    console.log(response);
  })
  .catch(function (error) {
    // 에러가 났을 때
    console.log(error);
  })
  .finally(function () {
    // 항상 실행되는 함수
  });
 

// 위와는 같지만, 옵션을 주고자 할 때는 이렇게 요청을 합니다.
axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  })
  .finally(function () {
    // always executed
  });  
 
 
// async/await 를 쓰고 싶다면 async 함수/메소드를 만듭니다. 
async function getUser() {
  try {
    const response = await axios.get('/user?ID=12345');
    console.log(response);
  } catch (error) {
    console.error(error);
  }
}

POST 요청

  • 웹 애플리케이션에서 서버로 데이터를 보내는 메서드
    • 데이터를 서버로 제출하거나 업데이트 할 때 (폼 데이터 전송, 파일 업로드)
    • 요청마다 새로운 정보 객체를 추가한다
  • 일반적으로 데이터를 Message Body에 담아서 보낸다.
axios.post("url", {
		firstName: 'Fred',
		lastName: 'Flintstone'
    })
    .then(function (response) {
        // response  
    }).catch(function (error) {
        // 오류발생시 실행
    })

PUT 요청

  • 데이터베이스에 저장되어 있는 내용을 갱신하기 위해 사용하는 메서드
    • 새로운 데이터 생성이 아닌, 기존의 데이터를 수정할 때 사용
  • 서버 내부적으로 GET → POST 과정을 거치므로, POST 메서드와 비슷한 형태를 가진다.
axios.put("url", {
        username: "",
        password: ""
    })
    .then(function (response) {
         // response  
    }).catch(function (error) {
        // 오류발생시 실행
    })

PATCH 요청

  • PUT과 동일하게 데이터를 수정하는데 사용하는 메서드
    • PUT과 비슷하지만, 리소스의 일부를 수정할 때 사용

💡 POST, PUT, PATCH 차이점

  • POST : Create / 생성 / 여러 번 호출 시 매번 다른 결과 생성
  • PUT : Update / 갱신, 생성 / 여러 번 호출 시 동일한 결과
  • PATCH : Partial Update / 일부 갱신 / 지정한 변경사항 일부만 변경

DELETE 요청

  • 데이터베이스에 저장되어 있는 내용을 삭제하기 위한 메서드
    • 일반적으로 body가 비어있다

      axios.delete('/user?ID=12345')
        .then(function (response) {
          // handle success
          console.log(response);
        })
        .catch(function (error) {
          // handle error
          console.log(error);
        })
    • 하지만 query나 params가 많아져서 헤더에 많은 정보를 담을 수 없을 경우에는
      - 두번째 인자에 data를 추가해서 사용한다.

      axios.delete('/user?ID=12345',{
          data: {
            post_id: 1,
            comment_id: 13,
            username: "foo"
          }
        })
        .then(function (response) {
          // handle success
          console.log(response);
        })
        .catch(function (error) {
          // handle error
          console.log(error);
        })

💡 보안적 문제 (PUT, DELETE)
PUT과 DELETE는 사용할 때 제대로 처리하지 않으면 보안적 문제가 발생할 수 있다.

  • PUT : 사용자 권한, 인증 관리 필요 (사용자 자신의 리소스만 업데이트 가능하도록)
  • DELETE : 실수로 데이터가 삭제되는 것을 방지 (복구 가능한 삭제 기능 구현)

메서드를 사용할 때 보안적 처리하는 방법
1. 인증 (Authentication)
2. 권한 부여 (Authorization)
3. 접근 제어 (Control Access)
4. 입력 유효성 검사 (Input Validation)


👀 fetch, axios를 사용했을 때 발생했던 통신 문제 트러블슈팅

발생한 문제

XMLHttpRequest 객체를 사용해서 통신했을 때는 문제가 없었지만, fetch or axios를 활용하는 경우에는 문제가 발생했었다.

  1. 요청은 성공적으로 보내졌으나 서버에 이미지 파일은 업로드 되지 않는 문제
  2. 이미지는 업로드 되어도 파일을 열면 이미지가 로드되지 않는 문제

정상적으로 통신되는 XHR 코드

var file = inputFileList[sendIndex].file;

if (!file) {
  console.error("파일을 선택하세요.");
  return;
}

var xhr = new XMLHttpRequest();
var serverUrl = `/upload/image/${inputFileList[sendIndex].name}`; // 실제 서버 URL로 수정해야 합니다.

xhr.open("POST", serverUrl, true);
xhr.onload = function () {
  console.log(xhr);
  if (xhr.status === 200) {
    console.log("파일 업로드 성공");
  } else {
    console.error("파일 업로드 실패");
  }
};

xhr.onerror = function () {
  console.log(xhr);
  console.error("파일 업로드 오류");
};

xhr.send(file); 

HTTP 요청방식 & 데이터 처리방식

  • 클라이언트와 서버간 통신은 각 구성에 따라 방법이 달라질 수 있다.
  • 지금 현재 상황은 서버가 특정 형식의 요청만 처리하는 형식이기 때문에 발생하는 문제라고 판단했다.
  • 여러가지의 문제점이 있지만, 요청 형식 및 데이터 형식이 올바르지 않아서 발생하는 문제라고 판단했다.

XMLHttpRequest방식

  • xhr.send(file) 에서 파일 객체를 직접 전송
  • 파일을 바이너리 타입으로 전송하고, 서버가 이를 처리하는 방식이다.

fetch API 방식

  • formData 객체를 사용해서 데이터를 전송
  • Content-Type: application/json이 아닌 Content-Type: multipart/form-data로 요청을 보낸다.
  • 서버는 formData로 전송된 데이터를 다르게 처리하므로 서버 환경 구성에 따라 추가로 고려해야한다.

fetch API를 사용해 바이너리로 파일 전송하기

  • 이전에 사용한 fetch API 코드
 let file = inputFileList[sendIndex].file;

if (!file) {
  console.error("파일을 선택하세요.");
  return;
}

try {
  const formData = new FormData();
  formData.append("file", file);

  const serverUrl = `/upload/image/${inputFileList[sendIndex].name}`;

  const response = await fetch(serverUrl, {
    method: "POST",
    body: formData,
  });

  if (response.ok) {
    console.log("파일 업로드 성공");
  } else {
    console.error("파일 업로드 실패");
  }
} catch (error) {
  console.error("파일 업로드 오류", error);
}
  • 파일데이터를 바이너리 형태로 전송하는 코드
    • FormData 객체 대신에 직접 파일 객체를 body에 전달하여 파일을 업로드
 let file = inputFileList[sendIndex].file;

if (!file) {
  console.error("파일을 선택하세요.");
  return;
}

try {
  const serverUrl = `/upload/image/${inputFileList[sendIndex].name}`;

  const response = await fetch(serverUrl, {
    method: "POST",
    body: file, // 파일 객체를 직접 body에 전달
  });

  if (response.ok) {
    console.log("파일 업로드 성공");
  } else {
    console.error("파일 업로드 실패");
  }
} catch (error) {
  console.error("파일 업로드 오류", error);
}

Axios 라이브러리 활용

  • fetch API를 활용해서 body에 직접 파일을 담아서 보내니, 문제 없이 이미지가 서버로 저장되는 것을 확인할 수 있었다.
  • 따라서 axios를 적용해서 코드를 먼저 변환했다.
let file = inputFileList[sendIndex].file;

if (!file) {
  console.error("파일을 선택하세요.");
  return;
}

try {
  const serverUrl = `/upload/image/${inputFileList[sendIndex].name}`;

  const response = await axios.post(serverUrl, file, {
    headers: {
      "Content-Type": "multipart/form-data", // FormData를 전송할 때 필요한 헤더 설정
    },
  });

  if (response.status === 200) {
    console.log("파일 업로드 성공");
  } else {
    console.error("파일 업로드 실패");
  }
} catch (error) {
  console.error("파일 업로드 오류", error);
}
  • 코드가 포함된 함수를 서버 이미지 업로드 버튼에 바로 연동했을 때는 문제없이 통신이 되었다.
  • 하지만 axios 코드를 api 폴더에 구분해서 관리하고자 폴더를 구분해서 작성했을때는 통신에러는 안나지만 파일이 로드되지 않는 문제가 다시 발생했다.

→ 해당 문제는 formData형식으로 보내서 계속 발생했던 문제였다.

  • axios 내용은 따로 api폴더에 관리하는 방식으로 해서 관리하는 방향으로 수정했다.

  • axios 폴더 코드

import axios from "axios";
// 이미지 업로드
export const uploadImage = async (fileInfo) => {
  try {
    const request = await axios.post(
      `/upload/image/${fileInfo.name}`,
      fileInfo.file,
      {
        headers: {
          "Content-Type": "multipart/form-data", // FormData를 전송할 때 필요한 헤더 설정
        },
      }
    );

    return request.data;
  } catch (error) {
    return "upload Image Faile";
  }
};
  • 통신 연결 코드
const uploadFile = async () => {
  try {
    const file = inputFileList[sendIndex];
    if (!file) {
      console.log("파일 존재하지 않음");
    }

    // API 통신
    await uploadImage(file); // uploadImage 함수가 완료될 때까지 기다림
    console.log("파일 업로드 성공");
  } catch (error) {
    console.error("파일 업로드 오류", error);
  }
};
profile
FrontEnd Developer.

0개의 댓글

관련 채용 정보