interceptor란?
inter 중간에서
cepter 가로채는
HTTP 통신을 할 때, 즉 요청을 하고 응답을 하는 그 중간에서 사이에서 뭔가를 가로채서 어떠한 것을 한다는 개념
interceptor의 필요성
axios.get("http://localhost:3001/todos");
axios.post("http://localhost:3001/todos", todo);
axios.delete(`http://localhost:3001/todos/${todoId}`);
위와 같이 호출하는 부분이 몇백개가 된다고 했을 때, 포트를 변경해야하는 경우 일일이 모든 주소를 바꾸는 것은 time-consuming 할 것이다. 또는, 요청할 때마다 console.log를 통해 로깅을 하려고 할 때도 몇백개의 console.log를 적는 것은 인적리소스 낭비이다.
그래서
interceptor는 요청과 응답 가운데에 껴서
(1) 요청(request)가 처리되기 전 http request가 서버에 전달되기전
(2) 응답(response)의 then(성공) 또는 catch(실패)가 처리되기 전
으로 프로세스를 나누고, 개발자가 그 중간단계에서 코드에 관여할 수 있게 해준다.
이외에도
- 요청 헤더 추가
- 인증 관리
- 로그 관련 로직 삽입
- 에러 핸들링
에 큰 도움이 된다.
실습1
이 코드에서 시작됩니다.
0. 리펙토링 개념으로 .env 파일 만들기
0-1. root scope에 .env 파일 만들기
0-2. 변수를 만들어 서버 주소 넣기
// .env
REAT_APP_SERVER_URL = http://localhost:3001
BEFORE
// 조회 함수
const fetchTodos = async() => {
const {data} = await axios.get('http://localhost:3001/todos');
console.log('response', data);
setTodos(data);
}
AFTER
// 조회 함수
const fetchTodos = async() => {
const {data} = await axios.get(`${process.env.REACT_APP_SERVER_URL}/todos`);
console.log('response', data);
setTodos(data);
}
server를 끄고 다시 실행시켜보면, 데이터가 잘 들어온것을 확인할 수 있다. 이제 나머지 URL도 모두 바꿔준다.
import axios from "axios";
import { useEffect, useState } from "react";
function App() {
const [todos, setTodos] = useState(null);
const [inputValue, setInputValue] = useState({
title: '',
});
const [editedId, setEditedId] = useState('');
const [editedContent, setEditedContent] = useState('');
// 조회 함수
const fetchTodos = async() => {
const {data} = await axios.get(`${process.env.REACT_APP_SERVER_URL}/todos`);
console.log('response', data);
setTodos(data);
}
// 추가 함수
const onSubmitHandler = async() => {
await axios.post('http://localhost:3001/todos', inputValue);
// 컴포넌트에도 랜더링되게 하기 (state 도 바꾸기)
// setTodos([...todos, inputValue ]);
fetchTodos();
}
// 삭제 함수
const onDeleteHandler = async(id) => {
await axios.delete(`http://localhost:3001/todos/${id}`);
setTodos(todos.filter((item)=> item.id !== id));
}
useEffect (() => {
//db로부터 값을 가져오기
fetchTodos();
}, [])
// 수정함수
const onUpdatedHandler = async() => {
await axios.patch(`http://localhost:3001/todos/${editedId}`,{
title: editedContent,
})
setTodos(todos.map((item)=>{
if(item.id == editedId){
return {...item, title: editedContent}
} else {
return item;
}
})
);
}
return (
<div>
{/* 수정 영역 */}
<form>
<input value={editedId} type="text" placeholder="수정할 아이디" onChange={(e) => {
setEditedId(e.target.value);
}}/>
<input value={editedContent} type="text" placeholder="수정할 내용" onChange={(e)=> {
setEditedContent(e.target.value);
}}/>
<button onClick={()=> onUpdatedHandler(editedId, editedContent)}>수정반영하기</button>
</form>
{/* input 영역 */}
<div>
<form onSubmit={(e)=>{
e.preventDefault();
// 버튼 클릭 시, input에 들어있는 값(state)를 이용하여 DB에 저장(post 요청)
onSubmitHandler();
setInputValue("");
}}>
<input value={inputValue.title} onChange={(ev)=>{
setInputValue({ title: ev.target.value});
}} type="text" />
<button type="submit">추가</button>
</form>
</div>
{/* 데이터 영역 */}
<div>
{todos?.map((item)=> {
return(
<div key={item.id}>
{item.id} : {item.title} <button onClick={()=> onDeleteHandler(item.id)}>삭제</button>
</div>
);
})}
</div>
</div>
);
}
export default App;
전체코드
import axios from "axios";
import { useEffect, useState } from "react";
function App() {
const [todos, setTodos] = useState(null);
const [inputValue, setInputValue] = useState({
title: '',
});
const [editedId, setEditedId] = useState('');
const [editedContent, setEditedContent] = useState('');
// 조회 함수
const fetchTodos = async() => {
const {data} = await axios.get(`${process.env.REACT_APP_SERVER_URL}/todos`);
console.log('response', data);
setTodos(data);
}
// 추가 함수
const onSubmitHandler = async() => {
await axios.post(`${process.env.REACT_APP_SERVER_URL}/todos`, inputValue);
// 컴포넌트에도 랜더링되게 하기 (state 도 바꾸기)
// setTodos([...todos, inputValue ]);
fetchTodos();
}
// 삭제 함수
const onDeleteHandler = async(id) => {
await axios.delete(`${process.env.REACT_APP_SERVER_URL}/todos/${id}`);
setTodos(todos.filter((item)=> item.id !== id));
}
useEffect (() => {
//db로부터 값을 가져오기
fetchTodos();
}, [])
// 수정함수
const onUpdatedHandler = async() => {
await axios.patch(`${process.env.REACT_APP_SERVER_URL}/todos/${editedId}`,{
title: editedContent,
})
setTodos(todos.map((item)=>{
if(item.id == editedId){
return {...item, title: editedContent}
} else {
return item;
}
})
);
}
return (
<div>
{/* 수정 영역 */}
<form>
<input value={editedId} type="text" placeholder="수정할 아이디" onChange={(e) => {
setEditedId(e.target.value);
}}/>
<input value={editedContent} type="text" placeholder="수정할 내용" onChange={(e)=> {
setEditedContent(e.target.value);
}}/>
<button onClick={()=> onUpdatedHandler(editedId, editedContent)}>수정반영하기</button>
</form>
{/* input 영역 */}
<div>
<form onSubmit={(e)=>{
e.preventDefault();
// 버튼 클릭 시, input에 들어있는 값(state)를 이용하여 DB에 저장(post 요청)
onSubmitHandler();
setInputValue("");
}}>
<input value={inputValue.title} onChange={(ev)=>{
setInputValue({ title: ev.target.value});
}} type="text" />
<button type="submit">추가</button>
</form>
</div>
{/* 데이터 영역 */}
<div>
{todos?.map((item)=> {
return(
<div key={item.id}>
{item.id} : {item.title} <button onClick={()=> onDeleteHandler(item.id)}>삭제</button>
</div>
);
})}
</div>
</div>
);
}
export default App;
1. instance 만들기, baseURL 설정하기
1-1. src > axios > api.js 만들기
1-2. 우리가 직접 만드는 instance 만들기
const data = axios.get("http://localhost:4000/");
기존 axios.get~ 방식은 순수 axios로 custom 설정이 되어있지 않은 instance(=axios)이다.
이제 api.js 파일에
import axios from "axios";
// 인자로 configuration 객체가 들어간다.
const instance = axios.create({
baseURL: process.env.REACT_APP_SERVER_URL,
});
export default instance;
1-3. App.jsx 에서 api import 하기
// import axios from "axios";
import { useEffect, useState } from "react";
import api from './axios/api';
1-4. axios 를 api로 바꾸기
1-5. ${process.env.REACT_APP_SERVER_URL} 를 지우기
결과코드
// import axios from "axios";
import { useEffect, useState } from "react";
import api from './axios/api';
function App() {
const [todos, setTodos] = useState(null);
const [inputValue, setInputValue] = useState({
title: '',
});
const [editedId, setEditedId] = useState('');
const [editedContent, setEditedContent] = useState('');
// 조회 함수
const fetchTodos = async() => {
const {data} = await api.get(`/todos`);
console.log('response', data);
setTodos(data);
}
// 추가 함수
const onSubmitHandler = async() => {
await api.post(`/todos`, inputValue);
// 컴포넌트에도 랜더링되게 하기 (state 도 바꾸기)
// setTodos([...todos, inputValue ]);
fetchTodos();
}
// 삭제 함수
const onDeleteHandler = async(id) => {
await api.delete(`/todos/${id}`);
setTodos(todos.filter((item)=> item.id !== id));
}
useEffect (() => {
//db로부터 값을 가져오기
fetchTodos();
}, [])
// 수정함수
const onUpdatedHandler = async() => {
await api.patch(`/todos/${editedId}`,{
title: editedContent,
})
setTodos(todos.map((item)=>{
if(item.id == editedId){
return {...item, title: editedContent}
} else {
return item;
}
})
);
}
return (
<div>
{/* 수정 영역 */}
<form>
<input value={editedId} type="text" placeholder="수정할 아이디" onChange={(e) => {
setEditedId(e.target.value);
}}/>
<input value={editedContent} type="text" placeholder="수정할 내용" onChange={(e)=> {
setEditedContent(e.target.value);
}}/>
<button onClick={()=> onUpdatedHandler(editedId, editedContent)}>수정반영하기</button>
</form>
{/* input 영역 */}
<div>
<form onSubmit={(e)=>{
e.preventDefault();
// 버튼 클릭 시, input에 들어있는 값(state)를 이용하여 DB에 저장(post 요청)
onSubmitHandler();
setInputValue("");
}}>
<input value={inputValue.title} onChange={(ev)=>{
setInputValue({ title: ev.target.value});
}} type="text" />
<button type="submit">추가</button>
</form>
</div>
{/* 데이터 영역 */}
<div>
{todos?.map((item)=> {
return(
<div key={item.id}>
{item.id} : {item.title} <button onClick={()=> onDeleteHandler(item.id)}>삭제</button>
</div>
);
})}
</div>
</div>
);
}
export default App;
따라서 앞으로 포트위치를 바꿔주고 싶다면, env에서만 바꿔주면 된다!
실습2
request, response 사이에서 코드에 관여하기
1. 기본 포맷
//api.js
import axios from "axios";
// 인자로 configuration 객체가 들어간다.
const instance = axios.create({
baseURL: process.env.REACT_APP_SERVER_URL,
});
instance.interceptors.request.use(
//요청을 보내기 전에 수행되는 함수
function(){},
//오류 요청을 보내기 전에 수행되는 함수
function(){}
)
instance.interceptors.response.use(
//응답을 내보내기 전 수행되는 함수
function(){},
//오류응답을 내보내기 전 수행되는 함수
function(){}
)
export default instance;
2. 채우기
import axios from "axios";
// 인자로 configuration 객체가 들어간다.
const instance = axios.create({
baseURL: process.env.REACT_APP_SERVER_URL,
});
instance.interceptors.request.use(
//요청을 보내기 전에 수행되는 함수
function (config) {
console.log("인터셉터 요청 성공!");
return config;
},
//오류 요청을 보내기 전에 수행되는 함수
function (error) {
console.log("인터셉터 요청 오류!");
return Promise.reject(error);
}
);
instance.interceptors.response.use(
//응답을 내보내기 전 수행되는 함수
function (response) {
console.log("인터셉터 응답 받았습니다");
return response;
},
//오류응답을 내보내기 전 수행되는 함수
function (error) {
console.log("인터셉터 응답 오류 발생");
return Promise.reject(error);
}
);
export default instance;
서버가 갑자기 안되서 해결해야함.
error Command failed with exit code 1.
'부트캠프 개발일지 2023-2024 > React 리액트' 카테고리의 다른 글
[10주차] 리액트심화: React Query 실습 (초기세팅, 데이터가져오기, 데이터입력하기) (0) | 2023.12.07 |
---|---|
[10주차] 리액트심화: React Query 이론과 개념 (2) | 2023.12.06 |
[9주차] 리액트심화: Axios VS Fetch (0) | 2023.11.28 |
[9주차] 리액트심화: 비동기 통신 axios(post, delete,patch) 하기 (0) | 2023.11.28 |
[9주차] 리액트심화: 비동기 통신 axios(get) 하기 (1) | 2023.11.28 |