현재 fileStoreService에서 예외가 발생하면 catch에 들어가서 예외처리가 발생하지만
동시에 파일이 다운로드되는 상황이 발생했다.
// 타임캡슐 파일 저장
@GetMapping(value = "/download/zip/timecapsule/{timecapsuleNo}/file")
public ResponseEntity<DataResponse<Map<String, Object>>> downloadZip(@PathVariable("timecapsuleNo") Long timecapsuleNo, HttpServletRequest request, HttpServletResponse response) throws IOException, InterruptedException {
try{
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.addHeader("Content-Disposition", "attachment; filename=" + new String((RandomStringUtils.randomAlphanumeric(6) + "-s3-download.zip").getBytes("UTF-8"), "ISO-8859-1"));
String prefix = getPrefix(request.getRequestURI(), "/s3/download/zip/");
fileStoreService.downloadZip(prefix, response, timecapsuleNo);
// 정상적인 경우
return new ResponseEntity<>(new DataResponse<>(200, "다운로드 성공"),
HttpStatus.OK);
}catch (CommonException e) {
// 예외 상황에 따른 ResponseEntity 반환
return new ResponseEntity<>(new DataResponse<>(e.getCustomExceptionStatus().getCode(), e.getCustomExceptionStatus().getMessage()),
HttpStatus.OK);
} catch (Exception e) {
// 기타 예외 처리
return new ResponseEntity<>(new DataResponse<>(500, "알 수 없는 에러가 발생했습니다. 잠시 후 다시 시도해주세요."), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
그 문제가 생겼던 이유는
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.addHeader("Content-Disposition", "attachment; filename=" + new String((RandomStringUtils.randomAlphanumeric(6) + "-s3-download.zip").getBytes("UTF-8"), "ISO-8859-1"));
여기서 발생했는데, Service에 들어가기 전에 response 헤더에 상태를 전부 설정해주어서
클라이언트는 정상적인 응답을 받았다고 판단했지만 실제로는 예외처리가 발생한 상황이 된 거다.
그래서 해결 방법으로 response를 service 안으로 옮겨버리기로 결정했다.
// (1)
// 서버 로컬에 생성되는 디렉토리, 해당 디렉토리에 파일이 다운로드된다
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.addHeader("Content-Disposition", "attachment; filename=" + new String((RandomStringUtils.randomAlphanumeric(6) + "-s3-download.zip").getBytes("UTF-8"), "ISO-8859-1"));
File localDirectory = new File(RandomStringUtils.randomAlphanumeric(6) + "-s3-download.zip");
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
// (2)
// TransferManager -> localDirectory에 파일 다운로드
MultipleFileDownload downloadDirectory = transferManager.downloadDirectory(bucket, prefix, localDirectory);
// (3)
// 다운로드 상태 확인
log.info("[" + prefix + "] download progressing... start");
DecimalFormat decimalFormat = new DecimalFormat("##0.00");
while (!downloadDirectory.isDone()) {
Thread.sleep(1000);
TransferProgress progress = downloadDirectory.getProgress();
double percentTransferred = progress.getPercentTransferred();
log.info("[" + prefix + "] " + decimalFormat.format(percentTransferred) + "% download progressing...");
}
log.info("[" + prefix + "] download directory from S3 success!");
// (4)
// 로컬 디렉토리 -> 압축하면서 다운로드
log.info("compressing to zip file...");
addFolderToZip(zipOut, localDirectory);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
// (5)
// 로컬 디렉토리 삭제
FileUtil.remove(localDirectory);
}
return new DataResponse<>(200, "성공");
위에서 예외처리가 다 끝나면 response에 넣어주는 방법으로 바꾸었다.
만약에 try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
여기 밑으로 response를 넣게 된다면 stream이 열려있기 때문에 실제로 헤더나 상태 코드의 변경은 이루어지지 않는 문제가 발생한다.
service로 response를 옮겨서 해당 문제를 해결할 수 있었다.