[React] CORS요..? 제 잘못,,, 인가요?

이준희·2021년 9월 8일
8

REACT 정복기

목록 보기
5/9

CORS요..? 흠,, 혹시 백엔드 쪽 문제 아닌가요..?

우리들의 숙명

프론트엔드 개발자로서 HTTP 통신은 프론트에서 다루는 가장 중요한 기술 중 하나라고 생각합니다.

빌트인 객체인 ① XMLHttpRequest 부터 ② fetch, ③ axios 까지 ajax 요청을 위한 다양한 빌트인 객체와 라이브러리가 존재합니다.

HTTP 리소스 요청 시에 자주 발생하는 CORS에러에 대해 프론트엔드 개발자가 백엔드 개발자에게 '백 쪽 문제 같은데 확인해주실 수 있나요?' 를 외칠 수 있는 명분을 만드는 과정에 대해서 이야기해봅니다.

가장 널리 사용되는 axios 모듈을 바탕으로 설명해볼까 합니다!

목차

① 헷갈리지 않는 기본 요청 보일러플레이트 만들어 놓기 🔥
② URL은 기본으로 🔥
③ config 설정하기 🔥

① 헷갈리지 않는 기본 요청 보일러플레이트 만들어 놓기 🔥

새내기 개발자의 입장에서 백엔드 URL에 바로 요청을 보내다보면, 어디서부터 뭐가 잘못됐는 지 헷갈리는 경우가 많습니다.

그래서 저의 경우는 기본적으로 작성해 둔 axios 보일러플레이트를 바탕으로 하나씩 차근차근 작업해 나갑니다.

axiosXMLHttpRequest 빌드인 객체에서 사용 가능한 HTTP 요청의 대부분을 지원합니다

axios 요청 시, 보낼 수 있는 Method (axios 모듈 참고)

axios 라이브러리에서 제공하는 인터페이스 확인하기

해당 메서드에서 cmd + 클릭 / ctrl + 클릭을 통해 다운 받은 axios 라이브러리에 접근이 가능합니다

따라서 제일 기본인 GET 요청을 바탕으로 무료로 JSON 데이터를 제공하고 있는 URL에 GET 요청을 보내 기본적으로 HTTP 통신이 가능한 상황인 지 파악해야 합니다.

URL에 접속하여 정확한 정보를 넘겨주는 지 확인해보는 것도 좋겠죠?

해당 코드는 다음과 같습니다.

$ npm i axios / $ yarn add axios
import axios from "axios";
import { useEffect, useState } from "react";

function Axios1() {
  const [res, setRes] = useState([]);

  useEffect(() => {
    console.log(res);
  }, [res]);

  const fetchData = async () => {
    try {
      await axios
        .get("https://jsonplaceholder.typicode.com/todos/")
        .then((res) => setRes(res.data.slice(0, 10)))
        .catch((err) => console.log(err));
    } catch (err) {
      console.log(err);
    }
  };
  return (
    <div
      style={{ borderBottom: "3px solid black", width: "100%", height: "50vh" }}
    >
      <h1>axios</h1>
      <button type="button" onClick={fetchData}>
        fetching!
      </button>
    </div>
  );
}

export default Axios1;

결과를 볼까요?

정상적으로 데이터가 넘어오는 것을 확인할 수 있습니다.

해당 배열을 바탕으로 객체 내부의 프로퍼티 키를 매핑 돌려서 원하는 구조와 형식으로 만들 수도 있습니다.

② URL은 기본으로 🔥

그렇다면 이제 실전입니다.

진행 중인 프로젝트의 백엔드 도메인으로 URL을 바꿔서 적용해봅니다.

하지만 흔히 MERN 스택(Mongo Express React Node) 과 같이 모든 서버가 같은 node.js 환경에서 두 개의 터미널을 열어 로컬 환경에서 작업할 수 있는 것은 아닙니다.

(나의 로컬환경에서 포트만 다르게 3000 <-> 8080처럼 작업할 경우가 적다는 얘기입니다)

현재 저의 경우 스프링 서버와 작업을 진행 중이며, 스프링 서버는 nginx를 사용하여 현재 배포되어 있는 상태입니다.

http://localhost:3000/ <-> https://api.xxx.com

따라서 로컬에서 https로 배포되어 있는 서버에 요청을 보내야하는 상황이기 때문에 필히 CORS가 발생할 수밖에 없겠죠..?

따라서 우리는 일종의 보험을 깔아두는 것처럼, 프론트에서 할 수 있는 최대한의 오픈 마인드를 갖추는 것이 필요합니다.

'모든 것을 다 허락할 거야' 와 같은 마인드죠

이런 정보는 header에 담게 되는데, HTTP 요청 시에 header 정보를 담아 요청을 보낼 수 있습니다.

axios 에서 header에 정보를 담기 위해서는 config를 설정해줘야 합니다.

HTTP 요청 시, 두 번째 파라미터에 config를 설정해줄 수 있습니다.

axios.get('https://api.velog.io/api/v1/posts', {
	...
})

url과 달리 config에는 (?) 가 붙은 것을 알 수 있습니다. 이는 옵션을 뜻하므로 넣어줘도 되고 안넣어줘도 된다는 것을 의미합니다.

③ config 설정하기 🔥

config로 설정할 수 있는 프로퍼티는 다음과 같습니다.

export interface AxiosRequestConfig {
  url?: string;
  method?: Method;
  baseURL?: string;
  transformRequest?: AxiosTransformer | AxiosTransformer[];
  transformResponse?: AxiosTransformer | AxiosTransformer[];
  headers?: any;
  params?: any;
  paramsSerializer?: (params: any) => string;
  data?: any;
  timeout?: number;
  timeoutErrorMessage?: string;
  withCredentials?: boolean;
  adapter?: AxiosAdapter;
  auth?: AxiosBasicCredentials;
  responseType?: ResponseType;
  xsrfCookieName?: string;
  xsrfHeaderName?: string;
  onUploadProgress?: (progressEvent: any) => void;
  onDownloadProgress?: (progressEvent: any) => void;
  maxContentLength?: number;
  validateStatus?: ((status: number) => boolean) | null;
  maxBodyLength?: number;
  maxRedirects?: number;
  socketPath?: string | null;
  httpAgent?: any;
  httpsAgent?: any;
  proxy?: AxiosProxyConfig | false;
  cancelToken?: CancelToken;
  decompress?: boolean;
  transitional?: TransitionalOptions
}

예를 들면

  const myConfig = {
    baseURL: 'https://api.velog.io/'
    withCredentials: true,
    headers: {
      Authorization: `Bearer ${myToken}`,
    },
  }

와 같은 방식으로 config를 설정해준 뒤, axios 요청에 함께 넣어줍니다.

  const loadUser = async () => {
    try {
      axios
      const result = await axios
        .get('/api/v1/users/profile', myConfig)
        .then((res) => console.log('result :', res.data))
      console.log(result)
    } catch (err) {
      console.log(err)
    }
  }

loadUser 함수와 같은 형식의 axios 요청을 보내게 될 것입니다.

① 헤더에 약속된 토큰을 넣어주고
② withCredentials: true로 설정한다면

거의 무적의 상태라고 볼 수 있습니다.

http 요청 standard 바로가기

그럼 이제 요청을 보내볼까요?

이제 당신이 할 일을 끝냈습니다
백엔드 개발자분께 대화를 요청해보세요!

선생님 CORS 문제가 있는 것 같습니다..! 😅

저도 위와 같은 프로세스를 경험하면서, 무조건 저의 문제라고 생각했던 부분이 의외로 백엔드에서 설정을 덜 한 부분이였던 경험이 있습니다.

모르는 만큼 더 많이 찾아보고, 백엔드 분들께 조심스럽게 요청을 한 경험이 있네요.

무작정 해보지 않고 물어보는 것보다는 내가 할 수 있는 경우의 수를 모두 작업해 본 뒤에 추가 확인 요청을 한다면, 협업시에 생길 수 있는 작은 다툼을 최소화할 수 있다고 생각합니다.

모두들 화이팅입니다!

profile
https://junheedot.tistory.com/ 이후 글 작성은 티스토리에서 보실 수 있습니다.

0개의 댓글