(참고) 프론트엔드는 React, 백엔드는 DRF로 개발하고 있습니다.
참고 부탁드립니다.
텍스트만 업로드 가능하던 기존 게시판에,
이미지도 업로드가 가능하도록 기능을 추가하다 마주친 에러입니다.
form 에 제목과 내용을 입력하고, 원하는 이미지를 선택한 뒤
업로드하기 버튼을 누르는 순간,
다음과 같은 에러가 발생하였습니다.
Broken pipe 에러가 발생했습니다.
Broken pipe 에러는 무엇이고, 언제 발생할까요?
Broken pipe 에러는 클라이언트와 서버의 통신이 비정상적으로 끊어질 때 발생합니다.
해야 하는 작업이 남아있는데, 완료 되기도 전에 모종의 이유로 연결이 끊어져버린 것이죠.
서버와 클라이언트의 비정상적인 통신중단 에러이니,
프론트엔드와 백엔드 둘 모두가 에러의 원인이 될 수 있기에,
프론트와 백 측의 코드를 모두 확인하며 잘못된 부분을 찾아야 합니다.
먼저 프론트엔드측 코드의 경우, 아래의 사항들을 점검해보아야 합니다.
백엔드 측 코드의 경우, 아래의 사항들을 점검해보아야 합니다.
저의 경우, 클라이언트 측의 코드에 문제가 있었습니다.
지금 생각해보면 정말이지 너무나 허무합니다.
아래는 문제가 되었던 코드 스니펫입니다.
const handleSubmit = async (e) => {
let multiTypeformData = new FormData();
multiTypeformData.append("title", formData.title);
multiTypeformData.append("content", formData.content);
multiTypeformData.append("author", author.id);
multiTypeformData.append("email", author.email);
//이미지가 있는 경우에만 업로드
if (image) {
multiTypeformData.append("image", image);
}
try {
await axiosInstance.post("create/", multiTypeformData, {
headers: {
"Content-Type": "multipart/form-data",
},
});
navigate("/home"); // 피드 화면으로 리다이렉팅
} catch (error) {
console.error("There was an error uploading the post!", error);
}
};
⬇️ axiosInstance 코드 참고
import axios from "axios";
const baseURL = "http://127.0.0.1:8000/api/";
const axiosInstance = axios.create({
baseURL: baseURL,
timeout: 5000,
headers: {
//django 설정 파일에서 simple jwt header type에 JWT주었음
Authorization: localStorage.getItem("access_token")
? "JWT " + localStorage.getItem("access_token")
: null,
"Content-Type": "application/json",
accept: "application/json",
// responseType: "json",
},
});
앞서, 프론트엔드측 코드의 경우, 아래의 사항들을 점검해보아야 한다고 했습니다.
제 코드의 경우 1번과 2번은 모두 문제가 없었습니다.
백엔드의 엔드포인트도 정확히 입력하였고,
기존 json형식이던 axiosInstance의 Content-Type도
이미지를 추가하며 "multipart/form-data" 로 덮어씌워 수정하였습니다.
제 코드의 경우, 3번 조건을 만족시키지 못하였습니다.
제 코드는, multiTypeformData를 서버로 보내지 못하고 있었습니다.
이유는, submit이벤트 핸들러에 브라우저의 디폴트 동작을 방지하는 코드 한 줄이 누락되었기 때문입니다.
e.preventDefault();
머리가 띵했습니다.
며칠을 고생했는데, 생각하지도 못한 이런 허무한 실수가 원인이었다니,
허탈한 웃음만 나왔습니다.
그래도, 이참에 위의 코드 한 줄이 어떤 기능을 하는지 제대로 정리해보겠습니다.
e.preventDefault();
는, form 을 제출했을 때 브라우저가 기본적으로 수행하는 동작을 차단해줍니다.
브라우저는 기본적으로 폼이 제출되면 페이지를 새로고침합니다.
문제는,
페이지가 새로고침되면 클라이언트와 서버의 연결이 끊어지고,
서버로 전송되어야 할 데이터가 중간에 유실될 수 있다는 것입니다.
이를 방지하고자 모든 submit이벤트 핸들러에선 e.preventDefault();
를 먼저 작성하고 내부 로직을 구현하는 것이 관례입니다.
오늘은 broken pipe에러에 대해 알아보았습니다.
해당 에러는 서버와 클라이언트의 연결이 비정상적으로 중단되어 발생하는 에러였습니다.
해당 에러가 발생하면, 아래의 사항들을 점검해보야 합니다.
프론트엔드
- 서버로 보내는 데이터의 형식(헤더의 Content-Type)이 유효한가? - axios 설정 확인
- 요청 엔드포인트가 정확한가?
- 데이터가 중간에 유실되지 않고 서버까지 무사히 도달할 수 있는가?
백엔드
- CORS 관련 설정이 잘 되어있는가?
- View 및 url 설정이 잘 되어있는가?
또한, 아주 기본적인 사항이지만,
폼 제출 이벤트 핸들러에선 반드시 브라우저의 디폴트 동작을 방지시켜주어야 합니다.
감사합니다.