通过RFC 5987处理带有空格的filename *参数会在文件名中生成“+”

我有一些我正在处理的遗留代码(所以我不能只使用带有编码文件名组件的URL),允许用户从我们的网站下载文件。 由于我们的文件名通常有许多不同的语言,因此它们都存储为UTF-8。 我写了一些代码来处理RFC5987转换为正确的文件名*参数。 这非常有用,直到我有一个非ascii字符空格的文件名。 根据RFC,空格字符不是attr_char的一部分,因此它被编码为%20。 我有新版本的Chrome和Firefox,他们都在下载时转换为%20到+。 我试过不编码空格并将编码的文件名放在引号中并获得相同的结果。 我已经嗅到了来自服务器的响应,以validationservlet容器没有弄乱我的标题,它们看起来对我来说是正确的。 RFC甚至包含%20的示例。 我错过了什么,或者所有这些浏览器都有与此相关的错误?

提前谢谢了。 我用来编码文件名的代码如下。

彼得

public static boolean bcsrch(final char[] chars, final char c) { final int len = chars.length; int base = 0; int last = len - 1; /* Last element in table */ int p; while (last >= base) { p = base + ((last - base) >> 1); if (c == chars[p]) return true; /* Key found */ else if (c < chars[p]) last = p - 1; else base = p + 1; } return false; /* Key not found */ } public static String rfc5987_encode(final String s) { final int len = s.length(); final StringBuilder sb = new StringBuilder(len << 1); final char[] digits = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; final char[] attr_char = {'!','#','$','&','\'','+','-','.','0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','^','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','|', '~'}; for (int i = 0; i >> 4)]; encoded[2] = digits[c & 0x0f]; sb.append(encoded); } } return sb.toString(); } 

更新

下面是我的评论中提到的带有空格的中文字符文件的下载对话框的屏幕截图。

下载对话框的屏幕截图

正如Julian在评论中指出的那样,我做了一个新手Java错误,忘了做我的字符到字节转换(因此我编码了字符的代码点而不是字符的字节表示),因此编码完全不正确。 RFC 5987中明确提到了这一点。我将发布用于进行转换的更正代码。 一旦编码正确,浏览器就会正确识别filename *参数,并且用于下载的文件名是正确的。

下面是更正的转义代码,它对字符串的UTF-8字节进行操作。 给我带来麻烦的文件名,现在正确编码,如下所示:

内容处置:附件; 文件名* = UTF-8”Museum%20%E5%8D%9A%E7%89%A9%E9%A6%86.jpg

 public static String rfc5987_encode(final String s) throws UnsupportedEncodingException { final byte[] s_bytes = s.getBytes("UTF-8"); final int len = s_bytes.length; final StringBuilder sb = new StringBuilder(len << 1); final char[] digits = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; final byte[] attr_char = {'!','#','$','&','+','-','.','0','1','2','3','4','5','6','7','8','9', 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','^','_','`', 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','|', '~'}; for (int i = 0; i < len; ++i) { final byte b = s_bytes[i]; if (Arrays.binarySearch(attr_char, b) >= 0) sb.append((char) b); else { sb.append('%'); sb.append(digits[0x0f & (b >>> 4)]); sb.append(digits[b & 0x0f]); } } return sb.toString(); }