인프런 커뮤니티 질문&답변
업로드시 POST http://localhost:3065/ 404 (Not Found) 에러질문입니다.
해결된 질문
작성
·
1.7K
0
antd upload컴포넌트를 사용해서 해당 강의를 학습하고 있습니다.
근데 이미지 업로드시 POST http://localhost:3065/ 404 (Not Found) 에러가 발생하고 있습니다.
redux툴을 확인해보니 아래와 같이 upload_images_success는 실행됬는데 redux의 imagepaths에는 파일명이 없습니다.



![app.js - prepare - Visual Studio Code [Administrator] 2022-09-24 오후 4_37_56.png app.js - prepare - Visual Studio Code [Administrator] 2022-09-24 오후 4_37_56.png](https://cdn.inflearn.com/public/files/posts/d88dc8b5-3fbc-452d-8f09-f1afd940eea6/app.js - prepare - Visual Studio Code [Administrator] 2022-09-24 오후 4_37_56.png)
확실하지는 않지만 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
정말 죄송한데 마지막으로 질문 하나만 드리겠습니다.
이미지를 업로드한 뒤 추가로 업로드하면 다음과 같이 이전 업로드를 포함해서 실행됩니다.

![index.js - prepare - Visual Studio Code [Administrator] 2022-09-24 오후 11_56_30 (2).png index.js - prepare - Visual Studio Code [Administrator] 2022-09-24 오후 11_56_30 (2).png](https://cdn.inflearn.com/public/files/posts/8ece29ae-cad9-4ec2-9fb8-c747500b0e59/index.js - prepare - Visual Studio Code [Administrator] 2022-09-24 오후 11_56_30 (2).png)

![index.js - prepare - Visual Studio Code [Administrator] 2022-09-24 오후 11_57_35 (2).png index.js - prepare - Visual Studio Code [Administrator] 2022-09-24 오후 11_57_35 (2).png](https://cdn.inflearn.com/public/files/posts/fc21d4aa-70eb-4280-9e61-386d7e61c29b/index.js - prepare - Visual Studio Code [Administrator] 2022-09-24 오후 11_57_35 (2).png)
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);
  }
});![index.js - prepare - Visual Studio Code [Administrator] 2022-09-25 오전 12_04_42 (2).png index.js - prepare - Visual Studio Code [Administrator] 2022-09-25 오전 12_04_42 (2).png](https://cdn.inflearn.com/public/files/posts/70605eb8-6493-4754-a346-3504e583a1e3/index.js - prepare - Visual Studio Code [Administrator] 2022-09-25 오전 12_04_42 (2).png)
![index.js - prepare - Visual Studio Code [Administrator] 2022-09-25 오전 12_04_44 (2).png index.js - prepare - Visual Studio Code [Administrator] 2022-09-25 오전 12_04_44 (2).png](https://cdn.inflearn.com/public/files/posts/b5e25eae-946e-4c27-99bb-ed9c1d94b792/index.js - prepare - Visual Studio Code [Administrator] 2022-09-25 오전 12_04_44 (2).png)
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,
    })
  }, []);
근데 실행하니 다음과같은 서버에러가 발생하네요 ㅜㅜ








.png)
리덕스에 들어있어서 그렇습니다. 리덕스에서 이미지 객체를 비우는 액션을 만들어 이미지 업로드 후 제거해세요.