프로젝트 유지보수 해야지 하다가 한달만에 .... 여러 수많은 에러를 겪었는데 적지 않아 기억이 나지 않는다
📌기본세팅
<javascript />
const api = axios.create({
baseURL: process.env.REACT_APP_API_URL,
headers: {
"content-type": "application/json",
},
withCredentials: true,
});
바로 에러 프로젝트에서 content-type을 두가지 사용해야 되서 두가지 적용을 해야하기 때문에 따로 빼야했다 ㅎㅎ
<javascript />
const instance = axios.create({
baseURL: process.env.REACT_APP_API_URL,
withCredentials: true,
});
📌axios.interceptors.request.use를 사용하여 모든 HTTP 요청을 가로채기
<javascript />
instance.interceptors.request.use(
async (config) => {
if (accessToken && !config.headers["Authorization"]) {
if (config.data instanceof FormData) {
config.headers["Content-Type"] = "multipart/form-data";
} else {
config.headers["Content-Type"] = "application/json";
}
config.headers["Authorization"] = `Bearer ${accessToken}`;
dispatch(
login({
accessToken,
memberId,
isLogin: true,
expire,
refreshToken,
})
);
}
return config;
},
(error) => {
Promise.reject(error);
}
);
여기서 config는 매개변수는 HTTP 요청 구성(config) 객체이다
여기에서 content-type을 정해주었다
꼭 리턴해주기 return config
=>수정된 요청 구성(config) 객체를 반환하여 해당 요청이 수정된 설정으로 실행되도록 하는 역할
instanceof는 자바스크립트에서 객체의 타입을 확인하는 연산자=>특정 객체가 특정 클래스의 인스턴스인지 아닌지를 검사하여 불리언 값을 반환한다
<javascript />
object instanceof constructor
constructor:테스트할 생성자
📌response interceptor에서는 HTTP 응답 객체를 검사하고, 만료된 토큰에 대한 처리를 수행 =>로그인 연장 처리하기
현재시간과 로컬스토리지에 저장되어있는 expire시간을 비교해 자동로그인 하는 로직을 추가했다
만약 이 조건이 참이라면, 서버에 새로운 토큰을 요청하여 토큰을 갱신해서 로그인 해야하는데 404에러뜨고 안돼서
콘솔로 찍으니 새로받은 토큰은 잘들어 왔지만 로그인 연장은 안돼서 한참 헤맸다 🥲
요청 객체의 구성(config)을 수정하지 않기 때문에 원래 요청 객체에 대한 정보가 손실될 가능성이 있다고 한다
<javascript />
instance.interceptors.response.use(
function (response) {
return response;
},
async function (error) {
if (isLogin && Date.now() >= expire) {
try {
const headers = {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
refreshtoken: `Bearer ${refreshToken}`,
};
const data = await axios({
url: `${process.env.REACT_APP_API_URL}/api/members/${memberId}`,
method: "GET",
headers,
});
console.log(data.headers);
const { refreshtoken: newRefreshToken, authorization } = data.headers; // refreshToken 변수 이름 변경
dispatch(
login({
accessToken: authorization,
memberId,
isLogin: true,
expire: Date.now() + 1000 * 60 * 60,
refreshToken: newRefreshToken,
})
);
return instance.request(error.config);
} catch (error) {
..////
}
}
return Promise.reject(error);
}
);
수정되지 않은 채로 원래의 요청을 보내게 되기 때문에 새로운 객체를 만들어주고 다시 Axios에 그객체를 넣어주고 리턴 해줘야한다
=> 수정된 newConfig 객체를 사용하여 Axios 요청을 다시 보내야한다
훅으로 만들었기 때문에 return instance해 주어야 한다
=>createAPIWithAuth 함수에서 생성한 인증 정보를 추가한 Axios 인스턴스를 리턴함으로써, 해당 인스턴스를 사용하는 쪽에서 인증 정보가 추가된 Axios 인스턴스를 이용하여 HTTP 요청을 보낼 수 있게 된다
<javascript />
//error.config.headers.Authorization = `Bearer ${authorization}`;
// error.config.headers.refreshtoken = `Bearer ${newRefreshToken}`;
const newConfig = { ...error.config };
newConfig.headers.Authorization = `Bearer ${authorization}`;
newConfig.headers.refreshtoken = `Bearer ${newRefreshToken}`;
return await axios(newConfig);
<javascript />
instance.interceptors.response.use(
function (response) {
return response;
},
async function (error) {
const { config, response } = error;
console.log(config);
console.log(response);
if (isLogin && Date.now() >= expire) {
try {
const headers = {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
refreshtoken: `Bearer ${refreshToken}`,
};
const data = await axios({
url: `${process.env.REACT_APP_API_URL}/api/members/${memberId}`,
method: "GET",
headers,
});
const { refreshtoken: newRefreshToken, authorization } = data.headers; // refreshToken 변수 이름 변경
dispatch(
login({
accessToken: authorization,
memberId,
isLogin: true,
expire: Date.now() + 1000 * 60 * 60,
refreshToken: newRefreshToken,
})
);
const newConfig = { ...error.config };
newConfig.headers.Authorization = `Bearer ${authorization}`;
newConfig.headers.refreshtoken = `Bearer ${newRefreshToken}`;
return axios(newConfig);
} catch (error) {
dispatch(
logout({
accessToken: null,
memberId: null,
isLogin: false,
refreshToken: refreshToken,
})
);
const headers = {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
refreshToken: `Bearer ${refreshToken}`,
};
await axios({
url: `${process.env.REACT_APP_API_URL}/api/members/logout`,
method: "POST",
headers,
});
localStorage.clear();
window.location.href = "/login";
window.location.reload();
}
}
return Promise.reject(error);
}
);
return instance;
};
axios 인스턴스를 만드는 대신에, 기존의 axios 에서 로그아웃 처리를 해주기
=> 새로운 axios 인스턴스를 만드는 오버헤드를 줄이고, 코드의 일관성을 유지할 수 있다
인터셉터를 사용하면 한결더 간결해지고 한곳에서 에러핸드링하기 좋다
느낀점:어렵다.. 실제적용하기 어렵다 우선은 되는데 제대로 된코드 인지 모르겠다... 간편하라고 만들었는데 일일히 토큰추가 하는게 인터셉터 적용하는것보다 수십배는 빠를것같닿ㅎ

'React' 카테고리의 다른 글
리액트 인풋 에러-Warning: A component is changing an uncontrolled input to be controlled. (0) | 2023.04.26 |
---|---|
리액트 중첩 라우팅(Nested Routing) (6) | 2023.03.24 |
느린컴포넌트 성능 향상가능한 useDeferredValue& useTransition(REACT 18) (6) | 2023.03.13 |
ref를 prop으로 넘기기( forWardRef) (6) | 2023.03.10 |
react query (5) | 2023.02.23 |