Spring + Ajax 파일 다운로드 시 Internet Explorer, Edge에서 한글이름 깨짐

기존 코드

	@GetMapping(value = "/download", 
				produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
	@ResponseBody
	public ResponseEntity<Resource> downloadFile(String fileName) {

		Resource resource = new FileSystemResource("D:\\upload\\" + fileName);
		String resourceName = resource.getFilename();

		HttpHeaders headers = new HttpHeaders();
		try {
			headers.add("Content-Disposition",
					"attachment; filename=" + new String(resourceName.getBytes("UTF-8"), "ISO-8859-1"));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return new ResponseEntity<Resource>(resource, headers, HttpStatus.OK);
	}

크롬(chrome)에서는 

D:\upload 폴더에 있는 파일의 이름과 확장자로 '\download?fileName=XXXX'와 같이 호출하면 브라우저는 자동으로 해당 파일을 다운로드 받는다.

 

But.

IE(Internet Explorer), Edge 같은 경우 Chrome 브라우저와 달리 한글 이름이 제대로 다운로드 되지 않는 경욱 있다. 그 이유는 헤더에 전달하는 Content_disposition의 값을 처리하는 방식이 IE, Edge같은 경우 Chrome과 달리 인코딩 방식이 다르기 때문이다.

 

 

 

 

 

해결 코드

  • HttpServletRequest에 포함된 헤더 정보들을 이용해서 요청이 발생한 브라우저가 IE인지 Chrome인지 Edge인지 확인해야 한다. 이를 위해 HTTP 헤더 메시지 중에서 디바이스의 정보를 알 수 있는 헤더는 'User-Agent' 값을 이용
        ※User-Agent: 브라우저의 종류 및 모바일인지 PC인지 알 수 있다.
  • @RequestHeader를 이용해 HTTP 헤더 메시지의 내용 중 User-Agent의 정보를 파악하여 각 브라우저 종류에 따라 다른 방식으로 처리해준다.

  • UUID를 제거하여(resourceOriginalName 생성) 순수하게 다운로드 되는 파일의 이름으로 저장될 수 있게 함
	@GetMapping(value = "/download", 
				produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
	@ResponseBody
	public ResponseEntity<Resource> downloadFile(@RequestHeader("User-Agent") String userAgent, String fileName) {

		Resource resource = new FileSystemResource("D:\\upload\\" + fileName);

		if (resource.exists() == false) {
			return new ResponseEntity<Resource>(HttpStatus.NOT_FOUND);
		}

		String resourceName = resource.getFilename();
		
		// remove UUID
		String resourceOriginalName = resourceName.substring(resourceName.indexOf("_") + 1);

		HttpHeaders headers = new HttpHeaders();
		try {

			String downloadName = null;
			
			// IE(Internet Explorer
			if (userAgent.contains("Trident")) {
				downloadName = URLEncoder.encode(resourceOriginalName, "UTF-8").replaceAll("\\+", " ");
			} 
			// Edge
			else if (userAgent.contains("Edge")) {
				downloadName = URLEncoder.encode(resourceOriginalName, "UTF-8");
			}
			else {
				downloadName = new String(resourceOriginalName.getBytes("UTF-8"), "ISO-8859-1");
			}


			headers.add("Content-Disposition", "attachment; filename=" + downloadName);

		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}

		return new ResponseEntity<Resource>(resource, headers, HttpStatus.OK);
	}