有什么方法可以让Android的默认浏览器识别“Content-Disposition:attachment”下载中的非ASCII文件名?

首先,我很确定这不是重复,因为我已经在StackOverflow和其他地方研究了这个主题很长一段时间了。 已经提出了类似的问题,但没有一个得到满意的回答。

过去的相关(但不完全相同)问题:

  • Android Chrome浏览器不必要地重命名已下载文件的名称和types
  • 如何在HTTP中编码Content-Disposition头文件名参数?

我也完全了解mod_rewrite技巧,这使得完全不必在HTTP头中处理文件名。 但是我们假设这不是一个选择。


大多数现代浏览器(IE9 +,Firefox,Chrome)在下载名称中包含非ASCII字符的文件时都支持RFC2231 / 5987 。 在这些情况下,以下PHP代码就像一个魅力:

 header("Content-Disposition: attachment; " . "filename*=UTF-8''" . rawurlencode($filename)); 

IE <= 8不了解RFC2231 / 5987,但以下代码大部分时间都有效。 由于每个浏览器都试图在某种程度上模拟IE,因此这也适用于许多其他浏览器,例如Firefox。

 header("Content-Disposition: attachment; " . 'filename="' . rawurlencode($filename) . '"'); 

同时,Chrome <11和Safari <6似乎更喜欢以下内容,尽管它将非ASCII字符直接放在标题中。

 header("Content-Disposition: attachment; filename=" . $filename); 

到现在为止还挺好。


但是当谈到Android的默认浏览器应用程序时,一切都崩溃了。 (到目前为止,我已经在姜饼,冰淇淋三明治和果冻豆中进行了测试。)

如果您给它标准的RFC2231 / 5987处理,默认浏览器完全忽略它并尝试从URL的最后部分猜测文件名。

如果你给它通常的非标准(IE <= 8)处理,默认浏览器会尝试将文件名解释为ISO-8859-1,导致无法理解的混乱字符,或者它会以静默方式丢弃所有非ASCII字符。 版本之间的确切行为有所不同,但无论如何,很明显Android的默认浏览器也不支持rawurlencode()格式。

如果将原始文件名放在标题中,则会发生同样的情况。

这通常不是第三方浏览器的问题,例如Firefox for Android,Dolphin Browser和Boat Browser。 默认浏览器应用程序是唯一一直无法理解UTF-8文件名的应用程序。


也许这最终在Android的最新版本中得到了修复,或者它可能会在下一个版本中修复。 但这不是我的问题。 我需要这个在现有设备中工作,并且仍然有数百万个Gingerbread和ICS设备。

我已经阅读了错误报告,我已经阅读了投诉,我已经阅读了很多关于这个问题的内容。 到目前为止,我一直无法find任何实际工作的编码方案。

如果有人知道如何 Content-Disposition **标题中编码非ASCII文件名**(例如файла파일ファイル名.jpg )并让Android默认浏览器识别它,请分享! 我不在乎它是多么hacky或非标准。 我不关心是否需要为每个版本的Android定制。

更新

不幸的是,到目前为止,我还没有收到任何能够解决上述问题的答案。 所以赏金到期无人认领。 请不要回答,除非您确实知道如何在ICS之前以Android浏览器识别的方式对非欧洲混合语言文件名进行编码,或者您有确凿的证据表明这是不可能的。

URLUtil.java负责guessFileName ,它调用parseContentDisposition ,它使用这个正则expression式"attachment;\\s*filename\\s*=\\s*(\"?)([^\"]*)\\1\\s*$"

根据Content-Disposition标头获取文件的文件名。

尝试复制parseContentDispositionfunction的源代码在我测试时正常工作。 例如,它返回файла파일ファイル名.jpg。

 import java.util.regex.Matcher; import java.util.regex.Pattern; public class HelloWorld{ public static void main(String []args){ String contentDisposition = "Content-Disposition: attachment; " + " filename=" +"\"файла파일ファイル名.jpg\""; Pattern CONTENT_DISPOSITION_PATTERN = Pattern.compile("attachment;\\s*filename\\s*=\\s*(\"?)([^\"]*)\\1\\s*$",Pattern.CASE_INSENSITIVE); try { Matcher m = CONTENT_DISPOSITION_PATTERN.matcher(contentDisposition); if (m.find()) { System.out.println("Result: " + m.group(2)); } } catch (IllegalStateException ex) { // This function is defined as returning null when it can't parse the header } } } 

可悲的是我现在无法测试它,但我使用以下代码将文件发送到浏览器,到目前为止我没有任何问题(即使使用android的浏览器)希望它可以帮助你:

  $formatRFC2231 = 'filename*=UTF-8\'\'%s'; $formatDef = 'filename="%s"'; switch ($useragent) { case "Opera": case "Firefox": $filename = rawurlencode($name); $format = $formatRFC2231; break; case "IE": case "Safari": case "Chrome": $filename = rawurlencode($name); $format = $formatDef; break; default: $filename = iconv("UTF-8", "ISO-8859-1//TRANSLIT", $name); $format = $formatDef; break; } 

这里的关键点是iconv函数,它可以转换ISO-8859-1中的任何非utf8字符

我相信您遇到了Android下载管理器中的错误,如下所述:

https://code.google.com/p/chromium/issues/detail?id=162333