해결된 질문
작성
·
1.6K
0
antd upload컴포넌트를 사용해서 해당 강의를 학습하고 있습니다.
근데 이미지 업로드시 POST http://localhost:3065/ 404 (Not Found) 에러가 발생하고 있습니다.
redux툴을 확인해보니 아래와 같이 upload_images_success는 실행됬는데 redux의 imagepaths에는 파일명이 없습니다.
확실하지는 않지만 antd upload에 action속성이 잘못되어서 오류가 발생하는것같은데 에러 원인에 대해서 알 수 있을까요?
참고 코드도 첨부하겠습니다.
uploadform
const normFile = useCallback((e) => {
console.log('Upload event:', e);
if (Array.isArray(e)) {
return e;
}
return e?.fileList;
}, []);
const onChangeImages = useCallback((e) => {
console.log('images', e.fileList);
const imageFormData = new FormData();
[].forEach.call(e.fileList, (f) => {
imageFormData.append('image', f);
});
dispatch({
type: UPLOAD_IMAGES_REQUEST,
data: imageFormData,
})
}, []);
<ImageUploaderWrapper
name="images"
rules={[
{
required: true,
message: '조리사진을 첨부하세요.',
},
]}
valuePropName="fileList"
getValueFromEvent={normFile}
>
{/* action: 파일을 업로드할 실제 URL -> localhost3065/images */}
<Upload.Dragger
name="image"
multiple
action="http://localhost:3065"
listType="picture"
onChange={onChangeImages}
>
<p style={{marginBottom: '0.5em'}}>Drag files here OR</p>
<Button type='primary' size='large' icon={<UploadOutlined />}>Upload</Button>
</Upload.Dragger>
</ImageUploaderWrapper>
redux
export const initialState = {
mainPosts: [],
imagePaths: [],
uploadImagesLoading: false, // 이미지 업로드
uploadImagesDone: false,
uploadImagesError: null,
};
export const UPLOAD_IMAGES_REQUEST = 'UPLOAD_IMAGES_REQUEST';
export const UPLOAD_IMAGES_SUCCESS = 'UPLOAD_IMAGES_SUCCESS';
export const UPLOAD_IMAGES_FAILURE = 'UPLOAD_IMAGES_FAILURE';
const reducer = (state = initialState, action) => {
return produce(state, (draft) => {
switch (action.type) {
case UPLOAD_IMAGES_REQUEST:
draft.uploadImagesLoading = true;
draft.uploadImagesDone = false;
draft.uploadImagesError = null;
break;
case UPLOAD_IMAGES_SUCCESS:
draft.imagePaths = action.data;
draft.uploadImagesLoading = false;
draft.uploadImagesDone = true;
break;
case UPLOAD_IMAGES_FAILURE:
draft.uploadImagesLoading = false;
draft.uploadImagesError = action.error;
break;
default:
break;
}
});
};
export default reducer;
saga
function uploadImagesAPI(data) {
return axios.post('/post/images', data);
}
function* uploadImages(action) {
try {
const result = yield call(uploadImagesAPI, action.data);
yield put({
type: UPLOAD_IMAGES_SUCCESS,
data: result.data,
})
} catch(err) {
yield put({
type: UPLOAD_IMAGES_FAILURE,
data: err.response.data
})
}
}
function* watchUploadImages() {
yield takeLatest(UPLOAD_IMAGES_REQUEST, uploadImages);
}
export default function* postSaga() {
yield all([
fork(watchUploadImages),
]);
}
router
try {
fs.accessSync('uploads');
} catch (error) {
console.log('uploads폴더가 존재하지 않아 생성합니다.');
fs.mkdirSync('uploads');
}
const upload = multer({
storage: multer.diskStorage({
destination(req, file, done) {
done(null, 'uploads');
},
filename(req, file, done) {
const ext = path.extname(file.originalname);
const basename = path.basename();
done(null, basename + '_' + new Date().getTime() + ext);
},
}),
limits: { fileSize: 20 * 1024 * 1024 },
});
router.post('/images', isLoggedIn, upload.array('image'), async (req, res, next) => {
try {
console.log(req.files);
res.json(req.files.map((v) => v.filename));
} catch (error) {
console.error(error);
next(error);
}
});
app.js
app.use('/', express.static(path.join(__dirname, 'uploads')));
답변 2
0
정말 죄송한데 마지막으로 질문 하나만 드리겠습니다.
이미지를 업로드한 뒤 추가로 업로드하면 다음과 같이 이전 업로드를 포함해서 실행됩니다.
onBeforeUpload를 사용해서 업로드 전에 조건을 줘서 첫 업로드를 제외하고 실행할 수 있을것같은데 혹시 이부분에 대해서 답변 받을 수 있을까요?
혼자 해결해보려고 계속 찾아봤는데 답을 찾기 힘들어서 질문드립니다.
postingform
const onChangeImages = useCallback((e) => {
const imageFormData = new FormData();
e.fileList.forEach((f) => {
imageFormData.append('image', f.originFileObj);
});
dispatch({
type: UPLOAD_IMAGES_REQUEST,
data: imageFormData,
})
}, []);
const onBeforeUpload = useCallback((file, fileList) => {
// Access file content here and do something with it
// console.log(file)
// Prevent upload
return false
}, []);
req.files 출력결과
router.post('/images', isLoggedIn, upload.array('image'), async (req, res, next) => {
try {
console.log('라우터', req.files);
res.json(req.files.map((v) => v.filename));
} catch (error) {
console.error(error);
next(error);
}
});
0
e.preventDefault()는 무슨 이유인지 실행이 안되서
다음과 같이 antd upload action속성을 주석처리하니까 에러는 해결됬습니다.
하지만 이후에도 back/images, redux의 imagePaths state에는 파일명이 저장이 안되네요 ㅜㅜ
<Upload.Dragger
name="image"
multiple
// action="http://localhost:3065" 주석처리하니 에러가 발생안함
listType="picture"
onChange={onChangeImages}
>
<p style={{marginBottom: '0.5em'}}>Drag files here OR</p>
<Button type='primary' size='large' icon={<UploadOutlined />}>Upload</Button>
</Upload.Dragger>
추가로 콘솔로확인해보니 FormData가 다음과 같이 비어있는 것을 확인했습니다.
saga
function uploadImagesAPI(data) {
console.log('사가의 데이터', data);
return axios.post('/post/images', data);
}
function* uploadImages(action) {
try {
const result = yield call(uploadImagesAPI, action.data);
yield put({
type: UPLOAD_IMAGES_SUCCESS,
data: result.data,
})
} catch(err) {
yield put({
type: UPLOAD_IMAGES_FAILURE,
data: err.response.data
})
}
}
upload form onChangeImages
const onChangeImages = useCallback((e) => {
console.log('images', e.fileList);
const imageFormData = new FormData();
[].forEach.call(e.fileList, (f) => {
imageFormData.append('image', f);
});
dispatch({
type: UPLOAD_IMAGES_REQUEST,
data: imageFormData,
})
}, []);
formData는 원래 콘솔에서 비어있습니다. 먼저 네트워크 탭에서 POST /post/images 요청에 payload에 formData가 들어있는지 보시고요. 서버쪽에서 console.log(req.files) 확인해보세요.
네트워크 payload를 확인해보니 다음과 같이 image에는 [object object]로 데이터가 들언간것같은데
서버에 작성한 console(req.files)는 출력되지 않네요 ㅜㅜ
back/routes/post.js
const upload = multer({
storage: multer.diskStorage({
destination(req, file, done) {
done(null, 'uploads');
console.log('upload1', req.files);
},
filename(req, file, done) {
const ext = path.extname(file.originalname);
const basename = path.basename();
done(null, basename + '_' + new Date().getTime() + ext);
console.log('upload2', req.files);
},
}),
limits: { fileSize: 20 * 1024 * 1024 },
});
router.post('/images', isLoggedIn, upload.array('image'), async (req, res, next) => {
try {
console.log('라우터', req.files);
res.json(req.files.map((v) => v.filename));
} catch (error) {
console.error(error);
next(error);
}
});
말씀해주신대로 event객체를 잘못 formData에 넣은것같아서 아래와 같이 수정했습니다.
const onChangeImages = useCallback((e) => {
console.log('images', e.fileList);
const imageFormData = new FormData();
// [].forEach.call(e.fileList, (f) => {
// imageFormData.append('image', f);
// });
e.fileList.forEach((f) => {
imageFormData.append('image', f.originFileObj);
});
dispatch({
type: UPLOAD_IMAGES_REQUEST,
data: imageFormData,
})
}, []);
근데 실행하니 다음과같은 서버에러가 발생하네요 ㅜㅜ
리덕스에 들어있어서 그렇습니다. 리덕스에서 이미지 객체를 비우는 액션을 만들어 이미지 업로드 후 제거해세요.