swfupload笔记
很早以前记的,放在草稿箱里,没有发出来,现发出来,因为是笔记,所以看起来可能比较乱。
swfupload是上传大文件、显示上传进度以及一次上传多个文件的很好选择。但由于其采用了flash做为上传的客户端,带来了以下问题:
- cookie无法和浏览器共享:如果你限制用户登录了后才能上传,那么,用户在浏览器里的cookie你要通过post的形式传过去。
- 跨域问题:若swfupload所用的swf文件和上传处理段不在同一域名,便有此跨域问题,解决倒也简单,在上传处理端加个crossdomain.xml即可。
crossdomain.xml示例:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd"> <cross-domain-policy> <site-control permitted-cross-domain-policies="all"/> <allow-access-from domain="*.swfuploadfile.com" /> <allow-http-request-headers-from domain="*" headers="*" /> </cross-domain-policy>
更让人头疼的是报2038错误(error=-200 message=#2038),这个错误实在折腾人啊。
先看看adobe官网是怎么说的:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/FileReference.html?filter_flash=cs5&filter_flashplayer=10.2&filter_air=2.6
里面讲到了ioerror出现的可能
- An input/output error occurs while the player is reading, writing, or transmitting the file.
- The SWF file tries to upload a file to a server that requires authentication (such as a user name and password). During upload, Flash Player or Adobe AIR does not provide a means for users to enter passwords. If a SWF file tries to upload a file to a server that requires authentication, the upload fails.
- The SWF file tries to download a file from a server that requires authentication, within the stand-alone or external player. During download, the stand-alone and external players do not provide a means for users to enter passwords. If a SWF file in these players tries to download a file from a server that requires authentication, the download fails. File download can succeed only in the ActiveX control, browser plug-in players, and the Adobe AIR runtime.
- The value passed to the
url
parameter in theupload()
method contains an invalid protocol. Valid protocols are HTTP and HTTPS.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/runtimeErrors.html
- 2038 File I/O Error.This error occurs when an application can't get file size, creation date or modification data using the FileReference API.
大概意思就是没有办法获得文件信息,另外一方面是由于上传接口需要http验证,无法输入用户名和密码无法所致。
那么先检查一下上传接口是否有上述问题(使用最原始的上传方式检查),如果上传接口正常,那么需要想想是不是客户端的问题了。有用户说杀毒软件会禁止flash上传,这个我没有实际的验证,但的确遇到过在同一swfupload系统,在有些客户端报2038错,而在其他的地方正常。
若所有的客户端都出现此问题,那么还是有可能上传接口的问题,我就碰到一例:
情况如下:
- 上传接口前面有一nginx做转发,且这个nginx距离实际处理上传文件的app服务器还有一段距离。
- 上传小文件正常,上传大文件会报2038 io error。
- 若不使用nginx转发,flash直接往app服务器上传文件,大文件也正常上传。
去检查nginx的log
cat nginx.log | grep Flash | awk '$12 == 413 {print $0}'
发现nginx的响应状态是499,而非正常的200。
怀疑nginx转发有问题,在客户端上传的同时,在nginx服务器上抓包看看:
sudo tcpdump -vvv -n -A host upload-app and port 80
发现nginx转发的request的post数据不全,同时upload-app服务器上给出的响应是 400 bad request。
至此,初步将原因定为flash player主动断开连接,因为本地的nginx log里面是499,关于499,http协议rfc2616中没有定义,通过相关资料查询可得,499为客户端(flash player)主动断开连接。关于nginx的499可以参考以下文章:
为什么flash会主动断开连接?我也不知。