簡體   English   中英

Java servlet下載文件名特殊字符

[英]Java servlet download filename special characters

我正在編寫一個簡單的文件下載servlet,我無法獲得正確的文件名。 嘗試URLEncoding和MimeEncoding文件名,如現有答案所示,但沒有一個工作。

以下代碼段中的fileData對象包含mime類型,byte []內容和文件名,至少需要ISO-8859-2字符集,ISO-8859-1是不夠的。

如何讓瀏覽器正確顯示下載的文件名?

以下是文件名的示例:árvíztűrőtükörfúrógép.xls,結果如下:árvíztqrptükörfúrógép.xls

  protected void renderMergedOutputModel(Map model, HttpServletRequest req, HttpServletResponse res) throws Exception {

    RateDocument fileData = (RateDocument) model.get("command.retval");
    OutputStream out = res.getOutputStream();
    if(fileData != null) {
        res.setContentType(fileData.getMime());
        String enc = "utf-8"; //tried also: ISO-8859-2

        String encodedFileName = fileData.getName();
            // also tried URLencoding and mime encoding this filename without success

        res.setCharacterEncoding(enc); //tried with and without this
        res.setHeader("Content-Disposition", "attachment; filename=" + encodedFileName);
        res.setContentLength(fileData.getBody().length);
        out.write(fileData.getBody());
    } else {
        res.setContentType("text/html");
        out.write("<html><head></head><body>Error downloading file</body></html>"
                .getBytes(res.getCharacterEncoding()));
    }
    out.flush();
  }

我發現解決方案適用於我安裝的所有瀏覽器(IE8,FF16,Opera12,Chrome22)。
它基於以下事實:如果沒有指定[不同]編碼,瀏覽器期望文件名參數中的值,這是在瀏覽器本機編碼中編碼的。

通常瀏覽器的本機編碼是utf-8(FireFox,Opera,Chrome)。 但IE的原生編碼是Win-1250。

因此,如果我們將值放入文件名參數,根據用戶的瀏覽器由utf-8 / win-1250編碼,它應該可以工作。 至少,它對我有用。

String fileName = "árvíztűrőtükörfúrógép.xls";

String userAgent = request.getHeader("user-agent");
boolean isInternetExplorer = (userAgent.indexOf("MSIE") > -1);

try {
    byte[] fileNameBytes = fileName.getBytes((isInternetExplorer) ? ("windows-1250") : ("utf-8"));
    String dispositionFileName = "";
    for (byte b: fileNameBytes) dispositionFileName += (char)(b & 0xff);

    String disposition = "attachment; filename=\"" + dispositionFileName + "\"";
    response.setHeader("Content-disposition", disposition);
} catch(UnsupportedEncodingException ence) {
    // ... handle exception ...
}

當然,這僅在上面提到的瀏覽器上進行測試,我無法100%保證這將在任何瀏覽器中始終有效。

注意#1(@fallen) :使用URLEncoder.encode()方法是不正確的。 盡管方法的名稱,它不會將字符串編碼為URL編碼,但它會編碼為表單編碼。 (表單編碼與URL編碼非常相似,在很多情況下它會產生相同的結果。但是存在一些差異。例如,空格字符''編碼不同:'+'而不是'%20')

對於正確的URL編碼字符串,您應該使用URI類:

URI uri = new URI(null, null, "árvíztűrőtükörfúrógép.xls", null);
System.out.println(uri.toASCIIString());

基於這里給出的優秀答案,我已經開發了一個擴展版本,我已經投入生產。 基於RFC 5987測試套件。

String filename = "freaky-multibyte-chars";
StringBuilder contentDisposition = new StringBuilder("attachment");
CharsetEncoder enc = StandardCharsets.US_ASCII.newEncoder();
boolean canEncode = enc.canEncode(filename);
if (canEncode) {
    contentDisposition.append("; filename=").append('"').append(filename).append('"');
} else {
    enc.onMalformedInput(CodingErrorAction.IGNORE);
    enc.onUnmappableCharacter(CodingErrorAction.IGNORE);

    String normalizedFilename = Normalizer.normalize(filename, Form.NFKD);
    CharBuffer cbuf = CharBuffer.wrap(normalizedFilename);

    ByteBuffer bbuf;
    try {
        bbuf = enc.encode(cbuf);
    } catch (CharacterCodingException e) {
        bbuf = ByteBuffer.allocate(0);
    }

    String encodedFilename = new String(bbuf.array(), bbuf.position(), bbuf.limit(),
            StandardCharsets.US_ASCII);

    if (StringUtils.isNotEmpty(encodedFilename)) {
        contentDisposition.append("; filename=").append('"').append(encodedFilename)
                .append('"');
    }

    URI uri;
    try {
        uri = new URI(null, null, filename, null);
    } catch (URISyntaxException e) {
        uri = null;
    }

    if (uri != null) {
        contentDisposition.append("; filename*=UTF-8''").append(uri.toASCIIString());
    }

}

不幸的是,這取決於瀏覽器。 請參閱主題討論此問題。 要解決您的問題,請查看此站點 ,其中包含不同標頭的示例及其在不同瀏覽器中的行為。

我最近在我的應用程序中解決了這個問題。 這里只是firefox的解決方案,它遺憾地在IE上失敗了。

response.addHeader(“Content-Disposition”,“attachment; filename * ='UTF-8'”+ URLEncoder.encode(“árvíztűrőtükörfúrógép”,“UTF-8”)+“。xls”);

private void setContentHeader(HttpServletResponse response, String userAgent, String fileName) throws UnsupportedEncodingException {
    fileName = URLEncoder.encode(fileName, "UTF-8");
    boolean isFirefox = (userAgent.indexOf("Firefox") > -1);
    if (isFirefox) {
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename*=UTF-8''" + fileName);
    } else {
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName);
    }
}

總結我到目前為止閱讀的所有內容對我有用:

URI uri = new URI( null, null, fileName, null);
    String fileNameEnc = uri.toASCIIString(); //URL encoded.
    String contDisp = String.format( "attachment; filename=\"%s\";filename*=utf-8''%s", fileName, fileNameEnc);
    response.setHeader( "Content-disposition", contDisp);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM