随笔-68  评论-567  文章-4  trackbacks-30

 

********************************************************************
*                                                 版权声明
*
* 本文以Creative Commons的知识共享署名-非商业性使用-相同方式共享发布,请严格遵循该授权协议。
* 本文首发于博客园, 此声明为本文章中不可或缺的一部分。
* 作者网名:    浪子
* 作者EMAILdayichen (at)163.com
* 作者BLOG:  Http://Www.Cnblogs.Com/Walkingboy
*
********************************************************************

[Flash FileUpload]用flash.net.FileReference实现无刷新文件上传

-Written by http://walkingboy.cnblogs.com/ (07-02-07)

摘要:

还在用UpdatePanel嘛?是否还为文件上传苦恼?

还在用Callback嘛?是否对文件上传无计可施?

还在用Ajax上传组件嘛?是否为其不稳定性而头疼不已?

兄弟忘了这些吧,让我们拾起古老的Flash,跟我一道将积蓄已久的无奈、郁闷踩于脚下......

一、楔子

一直都无法忘怀那段痴迷Flash的大学时代,从认识动画,到ActionScript,再到苦练鼠绘,所有付出的时间和睡眠都代表了我对Flash的情有独钟,曾经一直都在幻想毕业后可以从事Flash编程工作。可能自己的先天美感不足或者运气不佳,最终还是远离了自己一直钟爱的Flash。

时隔多年,Flash有了长足的发展,Flex更是呈现一片喜人的景象。

但是个人认为,如果Flash定位为富客户端,而不掺合服务端的推广,我相信现在的很多js类库将失去他们的市场。

喂,谁的臭袜子,稍微理解下我沉浸往事,不能自拔的心情嘛:)

二、上传难题

以前用UpdatePanel的时候,涉及到上传都只能在做一个小页面用Postback来做;

现在用Callback,还是只能使用新页面在Postback;

尝试过好几个Ajax 上传组件,最终败倒在其不稳定下。

昨天偶在codeproject查找资料,看到Flash 上传文件的介绍,才突然想起这个被自己遗忘在角落里的咚咚。

察看了下Flash 的API,发现FileReference和FileReferenceList对文件的上传支持已经相当的好了。 

事件摘要
事件        说明
onCancel = function(fileRef:FileReference) {}
当用户取消文件浏览对话框时调用。
onComplete = function(fileRef:FileReference) {}
当上载或下载操作成功完成时调用。
onHTTPError = function(fileRef:FileReference, httpError:Number) {}
当上载由于 HTTP 错误而失败时调用。
onIOError = function(fileRef:FileReference) {}
当发生输入/输出错误时调用。
onOpen = function(fileRef:FileReference) {}
当上载或下载操作开始时调用。
onProgress = function(fileRef:FileReference, bytesLoaded:Number, bytesTotal:Number) {}
在文件上载或下载操作期间定期调用。
onSecurityError = function(fileRef:FileReference, errorString:String) {}
当上载或下载由于安全错误而失败时调用。
onSelect = function(fileRef:FileReference) {}
当用户从文件浏览对话框选择要上载或下载的文件时调用。

基本上上传文件所需要的功能都有了。

三、SWF FileUpload

很久没有写ActionStcript,变得好生疏了,熟悉了一个下午才算缓过气来了。定下了这个上传组件的需求:

接受Handler:支持内嵌的HttpHandler处理和自定义的Aspx处理(提供传递参数)

进度条显示:计算总数和已上传数

提供结束JS事件:上传结束触发指定的js方法,并将文件名作为参数

花了一个晚上才写好这个swf,调用相当的简单 

     内嵌HttpHandler,不做任何处理的调用
         <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0"
                width="250" height="80" id="SWFFileUpload" align="middle">
                <param name="allowScriptAccess" value="sameDomain" />
                <param name="movie" value="SWFFileUpload.swf" />
                <param name="quality" value="high" />    
                <param name="FlashVars" value="CompletedFunction=OnCompleted">        
                <embed src="SWFFileUpload.swf" name="fileUpload1" align="middle" allowscriptaccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
            </object>

 使用内置的HttpHandler,需要在WebConfig配置HttpHandler信息: 

<httpHandlers>
    <add verb="*" path="SWFFileUpload.axd" type="SWFFileUpload.SWFFileUpload" validate="false"/>
</httpHandlers>

 

 然后文件会默认被上传到root/UploadFiles/底下,文件名与客户端文件名同,同名则覆盖 

        指定HttpHandler,指定参数    
        <br />
             <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0"
                width="250" height="80" id="Object1" align="middle">
                <param name="allowScriptAccess" value="sameDomain" />
                <param name="movie" value="SWFFileUpload.swf" />
                <param name="quality" value="high" />
                <param name="wmode" value="transparent">
                <%--flash组件的参数传递:
                    UploadPage:自定义的ASPX文件接受Handler
                    Args:传递到UploadPage的参数,最终以QueryString的形式传递,以;分割
                    CompletedFunction:上传结束后调用的js方法
                    FileExtension:上传文件类型过滤,以;分割
                    --%>
                <param name="FlashVars" value="UploadPage=CustomerHandler.aspx&Args=name=cdy;blog=walkingboy.cnblogs.com&CompletedFunction=OnCompleted&FileExtension=*.jpg;*.txt">
                <embed src="SWFFileUpload.swf" name="fileUpload2" align="middle"
                    allowscriptaccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
            </object>

         如果文件大的话,需要在webconfig配置(Macromedia官方声称可以支持100M的上传) 

<httpRuntime maxRequestLength="1550000"/>
 

四、扩展&Demo

目前我只做了单文件的上传,可以利用FileReferenceList将其扩展为多文件上传。

如果你的IE打了最新的补丁,你可能发现出现“单击以激活并使用此控件”的问题,可以考虑封装一个js类,来动态Writer swf object,就可以搞定这个问题。 

function FileUpload(){
return{
     Show:function(){
    //TODO:
     },
     Hide:function(){
    //TODO:
     }
}
}();

DEMO代码下载:SWFFileUpload.WetTest.rar
有些朋友使用过程中出现问题,没办法得到真正的错误信息,现将flash的源代码fla上传,有问题的朋友自己测试下吧: SwfFileUpload.fla updated by langzi at 07.11.21 
 Update 07.12.19 原来上传的swffileupload.fla丢失了,重新上传。

posted on 2007-02-09 11:27 浪子 阅读(9824) 评论(57)  编辑 收藏 所属分类: 妙手偶得

评论:
#1楼  2007-02-09 11:39 | chy710      
好东西
  回复  引用  查看    
#2楼  2007-02-09 11:55 | 青州男孩      
很不错的东西,回头研究一下!
  回复  引用  查看    
#3楼  2007-02-09 12:01 | Cameo      
如果能支持断点续传,就更好~
  回复  引用  查看    
#4楼  2007-02-09 12:04 | tianjj [未注册用户]
用vs2005打不开项目呀。

  回复  引用    
#5楼 [楼主] 2007-02-09 12:08 | 浪子      
@tianjj
WebApplication 请安装相关补丁。
或者按aspx样子自己建一个WebSite
  回复  引用  查看    
#6楼  2007-02-09 12:58 | threem0126 [未注册用户]
flash传文件是可以,但是它没法接收服务器端的返回信息,是为不足le
  回复  引用    
#7楼 [楼主] 2007-02-09 13:42 | 浪子      
@threem0126

确实是不足之处。
不知道可不可以js操作swf,如果可以的话就应该有办法实现额。

onHTTPError 不是是否处理服务端异常的?如果是倒是可以尝试用异常代替返回消息:)
  回复  引用  查看    
#8楼  2007-02-09 14:48 | Jeffrey Zhao      
据说JS是可以操作的Flash的。
这个可以用于做一个补充吧,如果用户装了Flash,那么就用Flash上传,否则就用隐藏的iframe。
  回复  引用  查看    
#9楼 [楼主] 2007-02-09 15:19 | 浪子      
@Jeffrey Zhao
一般Flash Player 90%都是会装的,除非这个人不上网 :)
把本来的ActvieX部署变为无需部署了
  回复  引用  查看    
#10楼  2007-02-09 15:28 | 大陆响尾蛇      
刚才还在为这个发愁。想在客服端能在上传对话框多选文件。好像里面没看到这个功能。能加上去吗?
  回复  引用  查看    
#11楼 [楼主] 2007-02-09 15:33 | 浪子      
@大陆响尾蛇
sorry,最近搞得头晕晕的,目前暂时没有打算增加这个,不过在CodeProject上看到一个是采用FileReferenceList的,它可以多选上传(原理是一样的,只不过多个循环)
http://www.codeproject.com/aspnet/FlashUpload.asp
  回复  引用  查看    
#12楼  2007-02-09 15:44 | Jeffrey Zhao      
@浪子
我是无所谓,可惜有些所谓的“Linux达人”追求标准到了不愿意为FireFox添加Flash插件的地步,还有些会隐藏所有Flash的。
  回复  引用  查看    
#13楼  2007-02-09 15:45 | guest [未注册用户]
能不能提供下swf的源文件
  回复  引用    
#14楼 [楼主] 2007-02-09 15:54 | 浪子      
@Jeffrey Zhao
呵呵,不过面对企业应用,FF只好靠边站:),我们很多都是Only IE的

  回复  引用  查看    
#15楼 [楼主] 2007-02-09 15:56 | 浪子      
#16楼  2007-02-09 16:18 | Jeffrey Zhao      
@浪子
I like that... :)
  回复  引用  查看    
#17楼 [楼主] 2007-02-09 16:32 | 浪子      
@Jeffrey Zhao
me too......
本来还想兼容,结果......不堪重负,终于决定ONLY IE Ver5.5+ ,世界一下子清静了,嘿嘿

  回复  引用  查看    
#18楼  2007-02-09 16:39 | Jeffrey Zhao      
@浪子
其实写一个不用Flash的并不复杂啊,而且有现成的例子。
你看现在主流Email不都有这个方法吗?
  回复  引用  查看    
#19楼 [楼主] 2007-02-09 16:41 | 浪子      
@Jeffrey Zhao
:),我说的是其他方面的,不是指FileUpload

  回复  引用  查看    
#20楼  2007-02-09 17:17 | 大陆响尾蛇      
@Jeffrey Zhao

flash 可以当客户端用。。不过微软(WPE/E)现在也有自己的产品了。。FLASH的地位要受到挑战了
  回复  引用  查看    
#21楼  2007-02-09 19:59 | Jeffrey Zhao      
@大陆响尾蛇
Flash和WPF/E都要插件,一时半会儿还无法取代现在的标准。
WPF/E还差Flash一段距离,呵呵。
  回复  引用  查看    
#22楼  2007-02-10 17:32 | guest [未注册用户]
研究了半天始终没有看到从哪里指定上传到服务器上的目录名,浪子可否告知一下?
  回复  引用    
#23楼  2007-02-10 17:34 | guest [未注册用户]
明白了,不好意思,嘿嘿
  回复  引用    
#24楼  2007-02-25 11:24 | tianjj [未注册用户]
能否提供fla文件。。
学习。。。
  回复  引用    
#25楼  2007-02-25 12:49 | YAO.NET℡      
嗯。这个不错。昨天我还在想进度条的实现,如果不采用这个API,可以用.net中文件上传的进度条实现原理,让flash获取进度信息。

http://www.cnblogs.com/yao/archive/2007/02/24/655190.html




  回复  引用  查看    
#26楼  2007-02-28 13:07 | A.Z [未注册用户]
@Jeffrey Zhao
我不是linux达人。我讨厌flash,打开某某网页一堆flash在上面闪,你看看你的cpu,你看看ie载入的速度,所以flash除非里面有我要用的东西,都一概禁止。
最近可能要做一个解决asp.net上上传问题的解决方案,我个人的见解是ajax(不是asp.net封装的ajax)+ws/wse.当然最终可能只是去看看一堆繁杂的代码,改动一下其中的致命细节,如果我按希望的这么做了,重新设计的cost不怎么划算。
  回复  引用    
#27楼  2007-03-05 10:39 | Fass [未注册用户]
浪子大哥:这地址"http://www.codeproject.com/aspnet/FlashUpload.asp"
Download source code - 351 Kb 下载不下来啊..能不能提供个别的.先谢谢了!
  回复  引用    
#28楼 [楼主] 2007-03-05 11:37 | 浪子      
@Fass
可以下载,可能你的网络的问题,我已经下载下来并放到cnblogs里面了,你可以从“http://www.cnblogs.com/Files/walkingboy/FlashUpload_src.zip” 下载

  回复  引用  查看    
#29楼 [楼主] 2007-03-05 11:39 | 浪子      
@A.Z
各种方案,都会有其利弊所在,看自己项目中的取舍点时如何的.目前感觉没有一种方法是十全十美的:)

  回复  引用  查看    
#31楼  2007-10-26 17:40 | geortin [未注册用户]
楼主,我把他加到我的项目里,上传文件时 弹出一个对话框,叫我输入用户名和密码,我输入了 浏览器就没响应了,请问什么原因啊
  回复  引用    
#32楼 [楼主] 2007-10-27 18:37 | 浪子      
你是说FancyUpload吗?这个要问楼上的那位.因为是他写的组件.

建议你直接用http://www.codeproject.com/aspnet/FlashUpload.asp 这个组件.

--引用--------------------------------------------------
geortin: 楼主,我把他加到我的项目里,上传文件时 弹出一个对话框,叫我输入用户名和密码,我输入了 浏览器就没响应了,请问什么原因啊
--------------------------------------------------------

  回复  引用  查看    
#33楼  2007-10-27 21:49 | geortin [未注册用户]
@浪子
我就是从http://www.codeproject.com/aspnet/FlashUpload.asp 上下载的FlashUpload_src.zip 单独运行他是没问题的,问题是加到我的网站里就出现对话框,叫我输入用户名和密码,百思不得其解,我的WEB.CONFIG和他是一致的呀,而且我的目录权限都放开了。
你说的楼上是谁呀。
  回复  引用    
#34楼  2007-10-29 08:35 | geortin [未注册用户]
博主你好,我把网站根目录下的web.config里这句去掉 <authorization>
<deny users="?"/>
</authorization>
可以传文件了,但是我怎么获得我刚刚上传的文件名呢,我要保存到数据库里呀。
  回复  引用    
#35楼 [楼主] 2007-10-30 01:28 | 浪子      
<authorization>
<deny users="?"/>
</authorization>
这部分设置是IIS的权限问题.


关于你说的文件名,上传的时候一定有一个处理上传的handle处理.在那里面做save的时候,就可以获得文件名.其实跟普通的postback的上传文件没有什么本质的区别.

具体的话,你看他的源码示例中的
public void ProcessRequest(HttpContext context)
{}

如果他没有给你挂事件的机会,你就在这个方法中挂一个自己的委托,上传完之后回调把文件名传回去就ok了.


--引用--------------------------------------------------
geortin: 博主你好,我把网站根目录下的web.config里这句去掉 &lt;authorization&gt;
&lt;deny users=&quot;?&quot;/&gt;
&lt;/authorization&gt;
可以传文件了,但是我怎么获得我刚刚上传的文件名呢,我要保存到数据库里呀。
--------------------------------------------------------

  回复  引用  查看    
#36楼  2007-10-30 15:59 | 小小风 [未注册用户]
<param name="FlashVars" value="UploadPage=CustomerHandler.aspx&Args=name=cdy;blog=walkingboy.cnblogs.com&CompletedFunction=OnCompleted&FileExtension=*.jpg;*.txt">

博主,请问一下。CustomerHandler.aspx如果后面我要加两三个参数怎么搞

CustomerHandler.aspx?id=<%=id%>&name=<%=name%>&ii=<%ii%>

老是提示要我输入;号。。
  回复  引用    
#37楼 [楼主] 2007-10-31 11:14 | 浪子      
这里的参数传递和url的不一样,你应该这样子传递

CustomerHandler.aspx?&Args=id=<%=id%>;name=<%=name%>;ii=<%ii%>

--引用--------------------------------------------------
小小风: &lt;param name=&quot;FlashVars&quot; value=&quot;UploadPage=CustomerHandler.aspx&amp;Args=name=cdy;blog=walkingboy.cnblogs.com&amp;CompletedFunction=OnCompleted&amp;FileExtension=*.jpg;*.txt&quot;&gt;

博主,请问一下。CustomerHandler.aspx如果后面我要加两三个参数怎么搞

CustomerHandler.aspx?id=&lt;%=id%&gt;&amp;name=&lt;%=name%&gt;&amp;ii=&lt;%ii%&gt;

老是提示要我输入;号。。
--------------------------------------------------------

  回复  引用  查看    
#38楼  2007-11-18 00:05 | 小风风 [未注册用户]
博主,我现在又有一个新的问题,实在找不到办法解决,又到你这来溜达了.

CustomerHandler.aspx?&Args=id=<%=id%>;name=<%=name%>;name1=<%ii%>
我传值的时候.一开始很正常,但是后来又出问题了,一碰到参数里带汉字的或者'-'小横的时候,传递就出乱码.出错.

汉字的话大部份是正常的,但比如 我传"超漂亮"这几个字的时候
CustomerHandler.aspx?id=1&name=超漂亮&name1=超漂亮

参数一正常

参数二:
当<globalization fileEncoding="utf-8" requestEncoding="utf-8" responseEncoding="utf-8" culture="zh-CN"/>
为:超漂�?name1=超漂�

当<globalization fileEncoding="gb2312" requestEncoding="gb2312" responseEncoding="gb2312" culture="zh-CN"/>
为:瓒呮紓浜?name1=瓒呮紓浜

参数三:错误

但有的时候其它汉字不会出错..

这个时候就会出错.我在.NET里搞了两天也没搞好,头痛啊
  回复  引用    
#39楼 [楼主] 2007-11-20 11:02 | 浪子      
@小风风
使用url编码,回服务端再解码。

  回复  引用  查看    
#40楼  2007-12-03 18:15 | xyz_boy [未注册用户]
有没有在VS2003下的版本?

05不会用...哭..
  回复  引用    
#41楼 [楼主] 2007-12-04 08:45 | 浪子      
请尝试去学会不会的东西,这是从事IT所必备的技能。

虽然这一个类库并不需要一定是vs2005

--引用--------------------------------------------------
xyz_boy: 有没有在VS2003下的版本?

05不会用...哭..
--------------------------------------------------------

  回复  引用  查看    
#42楼  2007-12-18 16:29 | linx [未注册用户]
SwfFileUpload.fla 好像不能下载啊,能否发一个到我邮箱呢
linxian163@163.com
谢谢。
  回复  引用    
#43楼 [楼主] 2007-12-19 09:16 | 浪子      
文件丢失了,已经重新上传,更正链接:)

--引用--------------------------------------------------
linx: SwfFileUpload.fla 好像不能下载啊,能否发一个到我邮箱呢
linxian163@163.com
谢谢。
--------------------------------------------------------

  回复  引用  查看    
#44楼  2007-12-22 15:16 | 巫云      
不错啊,支持。想问个问题:是直接Flex完成整个项目前台好,还是结合其他web方式(asp.net)好呢?
  回复  引用  查看    
#45楼 [楼主] 2007-12-24 09:38 | 浪子      
没有做过Flex的开发,不是很清楚。
以前版本的Flash和javascript,dom的沟通机制不是很通畅,新的Flex就不清楚了,太久没接触了:)

--引用--------------------------------------------------
巫云: 不错啊,支持。想问个问题:是直接Flex完成整个项目前台好,还是结合其他web方式(asp.net)好呢?
--------------------------------------------------------

  回复  引用  查看    
#46楼  2007-12-29 12:10 | 海之音 [未注册用户]
请问大侠:
如果要用jsp做后台,要那些改动啊?
  回复  引用    
#47楼 [楼主] 2008-01-03 08:35 | 浪子      
不要使用内置的HttpHanlder,修改成你自己的upload.jsp文件地址

--引用--------------------------------------------------
海之音: 请问大侠:
如果要用jsp做后台,要那些改动啊?
--------------------------------------------------------

  回复  引用  查看    
#48楼  2008-01-04 10:54 | alby [未注册用户]
Flash中直接upload("Upload.aspx")就可以了,简单明了,
不知楼主为什么非要搞这么复杂
Upload.aspx.cs:

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class UpLoad : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (Page.Request.Files.Count > 0)
{
string tempFile = Request.PhysicalApplicationPath;
for (int j = 0; j < Request.Files.Count; j++)
{
HttpPostedFile uploadFile = Request.Files[j];
if (uploadFile.ContentLength > 0)
{
uploadFile.SaveAs(string.Format("{0}{1}{2}", tempFile, "UploadFiles\\", uploadFile.FileName));
}
}
}
HttpContext.Current.Response.Write(" ");
}
}

  回复  引用    
#49楼 [楼主] 2008-01-04 11:51 | 浪子      
我本来就是用这个的嘛,只是提供外部结合的接口和配置而已:)

--引用--------------------------------------------------
alby: Flash中直接upload("Upload.aspx")就可以了,简单明了,
不知楼主为什么非要搞这么复杂
Upload.aspx.cs:

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class UpLoad : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (Page.Request.Files.Count > 0)
{
string tempFile = Request.PhysicalApplicationPath;
for (int j = 0; j < Request.Files.Count; j++)
{
HttpPostedFile uploadFile = Request.Files[j];
if (uploadFile.ContentLength > 0)
{
uploadFile.SaveAs(string.Format("{0}{1}{2}", tempFile, "UploadFiles\\", uploadFile.FileName));
}
}
}
HttpContext.Current.Response.Write(" ");
}
}

--------------------------------------------------------

  回复  引用  查看    
#50楼  2008-04-05 16:19 | dengxxdd [未注册用户]
老大,这个似乎不支持FF啊,我在FF里测试的时候上传完成后就会停止响应,是不是兼容性的问题?,
  回复  引用    
#51楼 [楼主] 2008-04-12 12:56 | 浪子      
按理应该是不会,因为flash 是跨平台的,你可以自己多测试下,或者下载源码自己debug...最近工作原因,无法帮忙调试,sorry.


--引用--------------------------------------------------
dengxxdd: 老大,这个似乎不支持FF啊,我在FF里测试的时候上传完成后就会停止响应,是不是兼容性的问题?,
--------------------------------------------------------

  回复  引用  查看    
#52楼  2008-04-28 20:00 | jole [未注册用户]
引用--------------------------------------------------
浪子: @guest
see:<a target="_new" href="http://www.codeproject.com/aspnet/FlashUpload.asp">http://www.codeproject.com/aspnet/FlashUpload.asp</a>

--------------------------------------------------------

请问 里的 <embed src="fileUpload.swf"
FlashVars='uploadPage=Upload.axd<%=GetFlashVars()%>
和配置档里
<httpHandlers>
<remove verb="POST,GET" path="Upload.axd"/>
<add verb="POST,GET" path="Upload.axd" type="Upload"/>
</httpHandlers>
什么意思?
如何调用到Upload.cs类的?
  回复  引用    
#53楼 [楼主] 2008-04-29 10:02 | 浪子      
只是个Hanlder,也可以是个网址。看你自己的写法了

你可以写成uploadPage=Upload.aspx也可以,只不过如果用相对地址的话,你可能要注意下路径的相对性。

所以我使用HttpHanlder,避过计算路径的问题。

  回复  引用  查看    
#54楼  2008-05-04 19:52 | jole [未注册用户]
@浪子
原来是这样谢谢
  回复  引用