상세 컨텐츠

본문 제목

👀인터셉터 가장 쉽게 알아보기 (✈공항 검색대?)

카테고리 없음

by maymj9798 2025. 1. 20. 20:19

본문

👉 인터셉터?

인터셉터는 ✈️공항 검색대 의 역할을 한다
우리는 해외로 갈 때,
출국 시에 가방 검사를 통해서 위험한 물건을 체크하고
입국 시에도 다시 한번 물건을 체크한다

🎈 요청(Request) 인터셉터

출국 시, 공항 검색대에서는 먼저 승객의 정보를 확인한다.

  • 비행기 표를 가지고 있는가 ?
  • 비자가 있는가 ?
  • 금지된 물건은 없는가 ?

위와 같은 기본 정보를 체크한다

이 과정은 리액트에서는
서버에 요청을 보내기 전에 체크를 해주는 것과 동일과정이다

  • 요청에 붙은 토큰을 확인하고 이를 통해 로그인 여부를 체크해준다
    (기본 사항인 비행기표와 비자가 있어??)
  • 서버에 보내기 전에 이상한 값이 있는지를 체크해준다
    (이상한 물건 없지??)

🎈 응답(Response) 인터셉터

입국 시, 공항 검색대에서는 위험 승객을 미리 거른다

응답 인터셉터 는 서버에서 응답을 받을때,
문제를 확인하거나 필요한 정보를 뽑아내준다

  • 주로 응답 인터셉터 에서는 로그인 실패 같은 에러를 던져준다

👉 왜 써?

✈️공항검색대가 없으면
항공사고가 많을거다 (각종 위법사항, 위험물건 소지 등등)
인터셉터는
미리 각종 문제를 검사해서 문제가 없도록 도와주는

*중간 다리 역할을 해준다 *

또한,
모든 검색을 한군데에서 모아서 하니까
각각의 요청마다 검사를 진행 할 필요없어서

코드가 깔끔해지는 장점이 있다

👉 어떻게 써?

리액트에서는 주로 Axios와 함께 쓴다

요청인터셉터 작성

  • 서버로 데이터를 보내기 전에 확인 및 수정 작업

🎈 1. Axios 인스턴스 생성

  • 서버와 통신하기 위한 Axios 인스턴스(객체)를 만들어서 통신 준비를 한다
    // 기본설정
    import axios from "axios";
    

const apiClient = axios.create({
baseURL: "기본 설정 URL",
headers: { "Content-Type": "application/json" },
})


### 👀  header 가 뭐야?

>헤더는 서버와 소통 할 때 보내는 `추가 정보`이다
편지 봉투에 쓰는 정보와 같은 거다

  - Content-Type = 보내는 데이터 종류를 서버에 알려준다 
  (서버에 데이터가 JSON 형식이라고 알려주는 거다)
  ```js
   headers: { "Content-Type": "application/json" }
  • Authorization = 누가 요청을 보내는지를 서버에 알려준다
    headers: { Authorization: "Bearer YOUR_TOKEN" }
  • 근데 왜 데이터 종류를 알려줘야 되는거야?
    서버는 다양한 데이터 형식을 받아
  • 그런데 서버 혼자서는 그 데이터가 어떤 형식인지 알수 없어*
    그래서 서버가 잘 해석할 수 있게
    미리 클라이언트(사용자)가 이 데이터는 이 형식이에요 라고 말을 해서
    해석을 도와주는거야

여기서 데이터 형식에는
JSON / HTML Form / XML 등등이 있어

🎈 2. 요청 인터셉터 추가

인스턴스를 생성했으면
이제 서버로 요청을 보내기 전에 실행하는
요청 인터셉터를 추가해야 해
*여기서는 주로 토큰추가, 데이터 검사, 로그 출력 등의 작업을 처리해 *

apiClient.interceptors.request.use(
    (config) => {
        토큰 설정 !
    }
)

토큰 설정법은 크게 로컬스토리지 / 쿠키 방법이 있다

  • 브라우저에 데이터를 저장한다는 공통점이 있다
  • 둘 다 브라우저를 새로고침하거나 닫아도 유지된다

📌 토큰 설정법 1 - 로컬스토리지

로컬스토리지 ??

  • 브라우저에 영구적으로 데이터를 저장하는 공간이야

  • 브라우저에만 저장이 되고, 서버로 자동 전송되지 않아
    서버로 보내려면 직접 요청을 해야해

  • 장점으로는 저장 방법이 간단하고 직관적이라는 점이 있어

  • 그리고 5MB 저장가능으로, 쿠키에 비해 많은 데이터를 저장해

  • 단점으로는 보안에 취약한 점이 있어
    그 이유는 개발자 도구를 통해 접근이 가능해
    그리고 악성 스크립트에 의해 탈취될 가능성이 있어

// 토큰 저장
localStorage.setItem('token', 'your_jwt_token');

// 토큰 가져오기
const token = localStorage.getItem('token');

📍 로컬스토리지를 인터셉터로 사용해보기

apuClient.interceptors.request.user(
  (config) => {
      const token = localStorage.getItem("token");
    if (token) {
        config.headers.Authorization = `Bearer ${token}`
        // 헤더에 토큰 추가 
    }
    return config;
  },
  (error) => {
      return Promise.reject(error);
  }
)

📌 토큰 설정법 2 - 쿠키

쿠키 ??

  • 서버에서 접속한 유저에게 너만 쓰라고 만들어주는 회원카드야
  • 손님은 이 카드를 들고 서버에 방문해
  • 그럼 서버는 손님이 들고 온 카드 정보를 통해 손님 데이터를 기억해
  • 기억하는 데이터에는 로그인 정보, 장바구니, 개인 설정(유튜브 알고리즘) 등등이 있다 !

*쿠키의 특징으로는
*
- 브라우저에 저장해 그리고 웹사이트 방문 할 때 자동으로 꺼내
= 모든 요청마다 서버에 자동으로 전송돼
(그래서 네트워크 트래픽이 늘어나는 단점이 있어)

  • 4kb 이하로, 아주 작은 데이터만 저장이 가능해
  • 유효기간을 설정해서 만료 시간을 설정 할 수 있어
    • 가장 짧으면 브라우저가 닫힐 때 ===> 이걸 세션 쿠키 라고 불러
    • 길게는 몇일, 몇달도 있어

쿠키의 단점은

  • 보안에 취약해 (XSS 공격)
  • 작은 용량 저장용이라 큰 데이터는 다른 방식을 써야 해

쿠키의 단점인 XSS 공격을 방어하기 위해
httpOnly 옵션을 설정해서 자바스크립트로 접근할 수 없게 만들수 있어

📍 쿠키를 인터셉터로 사용해보기

apiClient.interceptors.request.use(
  (config) => {
    const cookies = document.cookie.split("; ").reduce((acc, cookie) => {
      const [key, value] = cookie.split("=");
      acc[key] = value;
      return acc;
    }, {});

    const accessToken = cookies.accessToken; // 객체에서 바로 가져오기
    if (accessToken) {
      config.headers.Authorization = `Bearer ${accessToken}`;
    }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

✅ 순차적으로 설명

📕 1. 브라우저에서 쿠키에 접근

const cookies = doucument.cookie;

이 때 쿠키를 콘솔창에 찍어보면
access토큰 등 다양한 값을 확인 할 수 있다

accessToken=abc123; refreshToken=xyz789; theme=light

이거는 실제 어세스 토큰을 반환해준 쿠키를 콘솔창에 찍은 결과이다

'accessToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjQwNSwiaWF0IjoxNzM3MjEzNTE3LCJleHAiOjE3MzcyMjA3MTd9.0XkIKOspymdlJuPmpi5-plRSBsoqwBzpO6_2UR0703c'

📙 2. 한줄로 나온 값을 ;기준으로 나누어 배열로 만들기

doucument.cookie.split("; ")
// 결과값
[
  "accessToken=abc123",
  "refreshToken=xyz789",
  "theme=dark"
]

📒 3. 배열을 키와 값으로 나눠서 객체로 반환

cookies.reduce((acc, cookie) => {
  const [key, value] = cookie.split("="); 
  // '='로 key와 value 분리
  acc[key] = value; // 객체에 키-값 추가
  return acc;
}, {});
// 결과값
{
  accessToken: "abc123",
  refreshToken: "xyz789",
  theme: "dark"
}

📗 4. 뽑은 객체에서 accessToken 뽑아서 저장

const accessToken = cookie.accessToken;
// 결과값
"abc123"

📘 5. 받아온 값을 헤더에 추가

if (accessToken) {
  config.headers.Authorization = `Bearer ${accessToken}`;
}

🎯 6. 수정된 config 객체 반환

return config

config 객체는
Axios에서 요청을 보낼 때 필요한
URL, 메서드, 헤더 등을 포함하고 있는 객체야

만약 클라이언트가 get요청을 보냈고
이 요청이 인터셉터를 거치면
아래와 같은 config 객체를 가지게 돼

{
  baseURL: 'https://example.com/api', // API 기본 URL
  url: '/users',                     // 요청 경로
  method: 'get',                     // 요청 메서드
  headers: {                         // 요청 헤더
    Authorization: 'Bearer abc123'   // 요청 인터셉터에서 추가한 토큰
  },
  timeout: 0,                        // 요청 제한 시간 (기본값: 제한 없음)
  withCredentials: false,            // 쿠키 포함 여부
}

그리고 만약 POST 요청이라면
post요청의 body 값이
config객체에 data값이 추가가 되서 저장돼

{
  baseURL: 'https://example.com/api', // Axios 인스턴스의 기본 URL
  url: '/login',                     // 요청 경로
  method: 'post',                    // 요청 메서드
  headers: {                         // 요청 헤더
    'Content-Type': 'application/json', // 요청 데이터 형식
    Authorization: 'Bearer abc123'      // 인터셉터에서 추가한 토큰 (선택적)
  },
  data: {                            // 요청 데이터 (body)
    username: 'user123',
    password: 'password123'
  },
  timeout: 0,                        // 요청 제한 시간 (기본값: 제한 없음)
  withCredentials: false             // 쿠키 포함 여부
}

로컬스토리지 VS 쿠키

💡 httpOnly 옵션

위에서 쿠키의 단점인 XSS 공격을 방지하기 위해 httpOnly옵션을 사용한다고 했어

여기서 XSS 공격이란

  • 악성 스크립트를 통해 사용자의 브라우저에서 민감한 정보를 빼내는 공격이야
  • document.cookie 값을 읽는다면 사용자 인증 정보를 훔쳐 가겠지

이를 방지하기위해서

  • 자바스크립트로 쿠키에 접근하는 것을 막고
  • 서버와 통신 할 때 자동으로 쿠키를 포함하게 하는 기능이야

예시를 들어보면
보통 아파트 현관은
출입할 때 마다 비밀번호를 입력해야 해(쿠키)
근데 블루투스를 사용한 자동 출입기능을 사용하면
출입할 때 비밀번호를 누르지 않고 접근만 해도 자동으로 문이 열리는거랑 같은 거야

그런데 이 옵션은 클라이언트 측이 아닌 서버가 정하는 규칙이야
그래서 서버코드에 접근 할 수 없는 프론트엔드라면
주어진 설정 그래도 써야돼 ㅎ;

💡 withCredentials 옵션

이 옵션은 브라우저가 서버와 통신할 때
쿠키, 인증정보등을 요청에 포함해서 보낼지 말지를 정하는 옵션이야

이 옵션이 필요한 이유는
CORS환경 때문인데
CORS환경에서는 다른 도메인으로 요청을 보내면,
기본적으로 쿠키랑 인증정보를 빼고 보내게 설정되있어!

이때 withCredentials: true 옵션을 사용하면
다른 도메인으로 요청을 보내도
쿠키랑 인증정보가 같이 날라가

예시를 들어보면
클라이언트 주소는 http://naver.com
서버 주소는 http://api.movie.com
으로 다른 도메인이야
그럼 클라이언트 측에서 withCredentials옵션을 true로 변경해서 요청을 보내줘야해

axios.get('https://example.com/api', {
  withCredentials: true,
});

하지만 두 도메인이 같다면 withCredentials 옵션은 필요없어져!