나를 3일 동안 괴롭혔던 파일 다운로드의 대한 글을 작성한다.
- 파일명 한글이슈
- 다운로드된 콘텐츠의 길이가 잘리는 이슈
- FORM을 이용한 POST 요청을 웹서버에서 제한하는 이슈
- UTF-8 + BOM 대한 이슈
웹에서 파일을 다운로드하는 방식은 내가 알기론 두 가지로 나누어진다.
하나는 웹서버 프로그램을 통해 디스크 상에 있는 파일 그대로를 다운로드하는 경우와 또 하나는 프로그램에서 임의의 파일 내용을 출력하는 방법으로 다운로드하는 경우이다.
두 가지 모두 HTTP 헤더 값에 따라 브라우저가 그 콘텐츠를 다운로드할지 브라우저에서 보여줄지 결정된다. 웹서버는 실제 파일만을 취급하기 때문에 파일 속성에 따라 헤더가 결정되어 있지만 프로그램에서 임의의 파일 내용을 출력하는 경우는 직접 개발자가 헤더를 설정해야 한다.
response.setHeader("Content-Transfer-Encoding", "binary");
response.setHeader("Content-Disposition", "attachment; filename=\"" + docName + "\"");
첫 번째 이슈로 파일명에 관한 이야기다. 파일명은 문자셋에 따라 정말 복잡해진다. 한글은 조합형과 완성형으로 대개 둘 중 하나를 사용한다. 본론은 한글 완성형이나 utf-8로 된 문자로 된 경우는 파일명을 인코딩 또는 이스케이프 해야 한다.
이때 인코딩은 URL인코딩을 하면 된다. 하지만 JAVA의 경우 java.net의 URL Encoder.encode()를 이용했는데, 이 것은 URL을 인코딩한다고 하지만 실제로는 URL 인코딩 표준이 아니라 HTTP 폼 인코딩 표준에 따른다. 그래서 차이점이 존재하는데, 빈칸을 %20이 아니라 +로 인코딩하는 것이다. 이 때문에 브라우저가 URL을 받은 경우 빈칸이 제대로 바뀌지 않는다. 파일명이 ISO-8859-1이 아니면 무조건 인코딩을 해야 하는 것이다. 방법으로는 파일명의 +, 빈칸을 제한하는 방법과 최대한 영어로 된 파일 이름을 내려주는 것이 좋다.
웹서버에서는 Content-Type헤더를 설정하며, 그렇기 때문에 MIME 설정할 필요가 있다. MIME에 따라 브라우저가 파일을 어떻게 보여주는지 바뀌기도 한다. MIME종류는 수많은 종류가 존재하기 때문에 자주 쓰이는 형식 몇 가지와 특정 파일에 대한 MIME는 검색해서 사용하는 것이 좋다.
나 같은 경우에는 한글파일을 처리했기 때문에 검색을 통해 한글파일의 MIME를 설정해주었다.
response.setContentType("application/vnd.hancom.hml; charset=utf-8");
두 번째 이슈로 다운로드된 파일의 내용이 잘리는 이슈였다. 나는 a태그의 href를 이용해서 다운로드 요청을 보냈다. 이 말은 GET 요청을 통해 파일을 다운로드하는 경우인데, response헤더에 ContentLength에 파일 길이를 주었다.
response.setContentLength((int) file.length());
문제 첫 번째다. File 핸들러는 long형이고, 브라우저로 돌려줄 헤더 값에 넣은 파일 사이즈는 int형이므로 원래 파일 사이즈보다 작은 값이 설정되었다. 이경우 브라우저에서는 파일 크기와 헤더의 파일크기가 다르기 때문에 속도가 매우 느리며, 콘텐츠의 내용이 잘리기까지 했다. 찾아보니 원래 파일 사이즈 보다 클 경우 느리며, 원래 파일 사이즈보다 작을 경우 콘텐츠가 잘린다. 따라서 해당 헤더를 리턴하지 않기로 했다.
3번째 이슈 FORM 데이터 POST 요청 시 서버 설정
Tomcat가이드 문서에 따르면 기본 설정값은 2MB를 넘길 수없다. 또한 파라미터를 넘길 때 기본값은 만개이다.
server.xml의 maxPostSize 설정값과 maxParameterCount 설정값을 이용해 해결한다.
4번째 이슈 UTF +BOM
우선 BOM이란 Byte Order Mark의 약자로 해석하면 바이트 순서 표식이라고 할 수 있다.
매직넘버로 사용되며, 문서의 가장 앞에 추가하여 텍스트를 읽는 프로그램에 여러 가지 정보를 전달할 수 있다. 문서의 인코딩이 대부분 유니코드인 경우이며, 전달된 텍스트 문서의 다른 정보 없이도 처음 몇 바이트를 검사함으로 써 사용된 인코딩을 확인할 수 있다.
*BOM 문자가 데이터 스트림 중간에 등장할 경우 유니코드에서는 이를 폭과 줄 바꿈 없는 공백으로 해석해야 한다고 명시한다.
양식 파일을 읽는 경우 앞에 보이지 않는 바이트가 삽입되어 있어 데이터가 일치하지 않게 되었다. 그래서 기존 양식의 파일을 열어서 헥사 모드로 전향 후 문서의 인코딩 방식을 BOM 없는 UTF-8로 변경해 다시 저장한 후 에러를 해결했다.
UTF-8의 경우는 BOM이 하나로 고정이고 UTF-16, UTF-32는 Big Endian이냐, Little Endian이냐 구별한다.
그렇기에 UTF-8은 바이트 순서와 상관이 없기 때문에 출처가 명확한 문서를 읽는 경우에는 크게 필요가 없어 보여서 그냥 인코딩 방식을 변경한 것이다.
'웹 프로그래밍 기초' 카테고리의 다른 글
[css] z-index (0) | 2022.03.11 |
---|---|
Canvas (0) | 2021.10.17 |
주요 웹 서버 (0) | 2021.07.06 |
[CSS3] overflow (0) | 2021.07.05 |
[HTML] Mark Up literal (0) | 2021.06.06 |
댓글