http文件服务器下载接口中文,特殊字符问题
2017-08-24 14:57
155 查看
http文件服务器文件下载接口特殊字符及乱码问题
1.Content-Disposition作用
http文件的服务器下载文件的文件名判断是根据 Content-Disposition来识别。2.Content-Disposition编解码问题:
网上搜索解决方法及RFC规范发现Content-Disposition应该采用如下格式:Content-Disposition:attachment; filename="$encoded_fname"; filename*=utf-8''$encoded_fname
原因:
首先,根据 RFC 2616 所定义的 HTTP 1.1 协议( RFC 2068 是最早的版本;2616替代了2068并被最广泛使用,而后又被其他 RFC 替代,后文将会提及), HTTP 消息格式其实是基于古老的 ARPA Internet Text Messages ,而 ARPA 消息只能是 ASCII 编码的( RFC 822 Section 3 )。 RFC 2616 Section 2.2 更是再一次强调, TEXT( Section 4.2:Header 中的字段值即为 TEXT )中若要使用其他字符集,必须使用 RFC 2047 的规则将字符串编码/逃逸——必须要注意的是,这个规则原本是针对 MIME (电子邮件)的扩展,格式与百分号编码有很大不同。给一个在 MIME 中的例子:
Subject: =?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=
在1999年 RFC 2616 推出之时, Content-Dispostion 这个 Header 尚不是正式 HTTP 协议的一部分,只不过是因为被广泛使用而从 MIME 标准中直接借用过来了而已( RFC 2616 Section 19.5.1 )。因而几乎没有浏览器去支持 Content-Disposition 的多语言编码特性这样一个“扩展特性的扩展特性”。事实上,RFC 2616 中建议的使用 RFC 2047 来进行多语言编码的特性从未被主流浏览器支持过,所以我们也不用操心上面这个 MIME 方案了……
可是这个问题却的确是现实需要的,所以浏览器就各自想出了一些办法:
IE支持在 filename 中直接使用百分号编码:filename=”$encoded_text”(并非 MIME 编码!)。本来按照 RFC 2616 ,引号内的部分如果不是 MIME 编码,则应当直接被当作内容,就算它“看起来像是百分号编码后的字符串”;可是IE却会“自动”对这样的文件名进行解码——前提是该文件名必须有一个不会被编码的(即 ASCII)后缀名!
其他一些浏览器则支持一种更为粗暴的方式:允许在 filename=”TEXT” 中直接使用 UTF-8 编码的字符串!这也是直接违反了 RFC 2616 HTTP 头必须是 ASCII 编码的规定。
这两类浏览器的行为是彼此互不兼容的。所以你可以判断 UA 然后对IE使用前一种办法,其他浏览器使用后一种,这样便可以达到一般情况下能够 just work 的效果( Discuz 就是这么做的)。不过对于 Opera 和 Safari ,这样做可能不一定有效。
时代在进步,2010年 RFC 5987 发布,正式规定了 HTTP Header 中多语言编码的处理方式采用 parameter*=charset’lang’value 的格式,其中:
charset 和 lang 不区分大小写。
lang 是用来标注字段的语言,以供读屏软件朗诵或根据语言特性进行特殊渲染,可以留空。
value 根据 RFC 3986 Section 2.1 使用百分号编码,并且规定浏览器至少应该支持 ASCII 和 UTF-8 。
当 parameter 和 parameter* 同时出现在 HTTP 头中时,浏览器应当使用后者。
其好处是保持了向前兼容性:一来 HTTP 头仍然是 ASCII-only ,二来不支持该标准的旧版浏览器会按照当年 RFC 2616 的规定,把 parameter* 整体当作一个 field name ,从而当作一个未知的字段来忽略。随后,2011年 RFC 6266 发布,正式将 Content-Disposition 纳入 HTTP 标准,并再次强调了 RFC 5987 中多语言编码的方法,还给出了一个范例用于解决向后兼容的问题:
Content-Disposition: attachment;
filename=”EURO rates”;
filename*=utf-8”%e2%82%ac%20rates
这个例子里,filename 的值是一个同义英语词组——这样符合 RFC 2616 ,普通的字段不应当被编码;至于使用 UTF-8 只是因为它是标准中
a1f1
强制要求必须支持的。然而,如果我们再仔细想想——目前市场上常见的旧版本浏览器多为 IE 。如此一来,我们可以适当变通一下,将 filename 字段也直接使用百分号编码后的字符串:
Content-Disposition: attachment;
filename=”%e2%82%ac%20rates.txt”;
filename*=utf-8”%e2%82%ac%20rates.txt
对于较新的 Firefox 、 Chrome 、 Opera 、 Safari 等浏览器,都支持并会使用新标准规定的 filename* ,即使它们不会自动解码 filename 也无所谓了;而对于旧版本的IE浏览器,它们无法识别 filename* ,会将其自动忽略并使用旧的 filename(唯一的小瑕疵是必须要有一个英文后缀名)。这样一来就完美解决了多浏览器的多语言兼容问题,既不需要 UA 判断,也较为符合标准。
RFC:
http://www.ietf.org/rfc/rfc1806.txt
http://www.ietf.org/rfc/rfc2616.txt
3.Java处理
/** * 下载文件时的文件名编码问题 * @param fileStream * @return */ private void setContentDisposition(HttpServletRequest request, HttpServletResponse response, FileStream fileStream){ try { String fileName = fileStream.getFileName(); //1. 文件名为空不处理 if (StringUtils.isNullOrEmpty(fileName)){ return; }; //2. 文件名编码过滤 fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20"); //3. 设置response头 StringBuilder sbFileName = new StringBuilder(); sbFileName.append("attachment"); sbFileName.append(";filename="); sbFileName.append(fileName); sbFileName.append(";filename*=utf-8''"); sbFileName.append(fileName); response.setHeader("Content-Disposition", sbFileName.toString()); } catch (Exception e){ LOGGER.error("", e); } }
4.抓包实例
GET /rcs/networkapi/fnfiledownload?FileTransID=4z8w3w3u-7qq5-1035-8622-b1cf1926fb1d HTTP/1.1 Host: 10.10.12.88:8003 Connection: keep-alive Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0 Referer: http://10.10.12.88:8003/rcs/networkapi/fileview?FileTransID=4z8w3w3u-7qq5-1035-8622-b1cf1926fb1d Accept-Encoding: gzip, deflate, sdch Accept-Language: zh-CN,zh;q=0.8 HTTP/1.1 200 OK Server: grizzly/2.3.22 Accept-Charset: utf-8 Content-Disposition: attachment;filename=%E6%96%87%E6%9C%AC%E6%96%87%E4%BB%B6%2B%201111%26%3B%24%28%27%28%26%28.txt;filename*=utf-8''%E6%96%87%E6%9C%AC%E6%96%87%E4%BB%B6%2B%201111%26%3B%24%28%27%28%26%28.txt Content-Type: application/octet-stream;name= , + 1111&;$('(&(.txt Date: Thu, 24 Aug 2017 06:36:13 GMT Content-Length: 12 111123456789
参考:
http://www.cnblogs.com/hihtml5/p/7220188.html?utm_source=itdadao&utm_medium=referral
相关文章推荐
- Qt解决QUrl含有中文或特殊字符无法下载的问题
- 密码中有特殊的字符IOS如何处理 IOS中URL包含中文参数的问题
- 请求Http时可能因为字符问题导致错误的特殊字符转码
- javascript解决中文传递乱码和特殊字符问题
- iOS 密码中有特殊的字符IOS如何处理 IOS中URL包含中文参数的问题
- #面试题#URL带有中文或者其他特殊字符时错误的问题
- PHP处理中文字符串中的特殊字符解决Oracle插入报错的问题
- Apache HTTP Server路径不支持中文字符问题的解决办法
- 工作问题:http下载文件,中文文件名在firefox下乱码问题
- C++中使用IXMLHTTPRequest对象调用Web API时,对URL中的特殊字符(或中文)编码
- iText7彻底解决中文问题、特殊字符(如......省略号报错问题,其他的自测)
- tomcat容器下 http 请求参数中特殊字符(+、&、%)的问题
- URL中文乱码的问题,特殊字符的解决办法
- jmeter随笔(5)--断言中正则表达式的特殊字符问题和中文乱码显示问号的问题
- C# httprequest post 内容有百分号,部分特殊字符乱码问题
- iOS 中的 url 中文和特殊字符编码问题
- http下载文件中文文件名在firefox下乱码问题[转]
- 解决httpClient接口访问web时返回中文字符乱码问题
- Java HttpURLConnection模拟请求Rest接口解决中文乱码问题
- HTTP 文件下载时中文文件名乱码问题处理