分享
 
 
 

在ASP.NET中跟踪和恢复大文件下载

王朝asp·作者佚名  2006-11-24
窄屏简体版  字體: |||超大  

HttpHandler类:ZIPHandler

在ASP.NET中映射了.zip扩展名之后,客户端每次向服务器请求.zip文件的时候,IIS调用ZipHandler类的ProcessRequest方法(见下载代码)。

ProcessRequest方法首先建立自定义的FileInformation类(见下载代码)的一个实例,它封装了下载的状态(例如进行中、被中断了等等)。示例把download.zip示例文件的路径硬编码到代码中了。如果把这段代码应用于你自己的应用程序,需要修改它来打开被请求的文件。

' 使用objRequest检测请求了哪个文件,用该文件打开objFile。

' 例如objFile = New Download.FileInformation(<完整文件名>)

objFile = New Download.FileInformation( _

objContext.Server.MapPath("~/download.zip"))

接下来,程序使用描述的HTTP头信息(如果请求提供了头信息)执幸幌盗械难橹ぜ觳椤K衙恐旨觳槎挤庾霸谛⌒退接泻校绻橹こ晒Φ幕熬头祷豑rue。如果某个验证检查失败了,响应会立即终止,并发送适当的StatusCode值。

If Not objRequest.HttpMethod.Equals(HTTP_METHOD_GET) Or Not

objRequest.HttpMethod.Equals(HTTP_METHOD_HEAD) Then

' 目前只支持GET和HEAD方法

objResponse.StatusCode = 501 ' 没有执行

ElseIf Not objFile.Exists Then

' 无法找到被请求的文件

objResponse.StatusCode = 404 ' 没有找到

ElseIf objFile.Length > Int32.MaxValue Then

' 文件太大了

objResponse.StatusCode = 413 ' 请求实体太大

ElseIf Not ParseRequestHeaderRange(objRequest, alRequestedRangesBegin, alRequestedRangesend, _

objFile.Length, bIsRangeRequest) Then

' Range请求中包含无用的实体

objResponse.StatusCode = 400 ' 无用的请求

ElseIf Not CheckIfModifiedSince(objRequest,objFile) Then

' 实体没有被修改过

objResponse.StatusCode = 304 ' 没有被修改过

ElseIf Not CheckIfUnmodifiedSince(objRequest,objFile) Then

' 实体在上次被请求的日期之后被修改过

objResponse.StatusCode = 412 ' 预处理失败

ElseIf Not CheckIfMatch(objRequest, objFile) Then

' 实体与请求不匹配

objResponse.StatusCode = 412 ' 预处理失败

ElseIf Not CheckIfNoneMatch(objRequest, objResponse,objFile) Then

' 实体的确与none-match请求匹配。

' 响应代码位于CheckIfNoneMatch函数中

Else

' 初步检查成功

这些初步检查的函数中的ParseRequestHeaderRange(见下载代码)检查客户端是否请求了文件范围(这意味着是一个局部下载)。如果被请求的范围是无效的(无效范围指超越文件大小或包含不合理数字的范围数值),该方法把bIsRangeRequest设置为True。如果请求了范围,CheckIfRange方法会验证IfRange头信息。

如果被请求的范围是有效的,代码会计算响应信息的大小。如果客户端请求了多个范围,响应信息大小的数值会包含多部分头部信息长度的数值。

如果不能确定某个发送的头部信息值,程序将把这个下载请求作为最初请求而不是部分下载来处理,从文件的顶部开始发送一个新的下载流。

If bIsRangeRequest AndAlso CheckIfRange(objRequest, objFile) Then

' 这是范围请求

' 如果Range数组包含多个实体,它还是一个多部分范围请求

bMultipart = CBool(alRequestedRangesBegin.GetUpperBound(0)>0)

' 进入每个范围来获取整个响应长度

For iLoop = alRequestedRangesBegin.GetLowerBound(0) To alRequestedRangesBegin.GetUpperBound(0)

' 内容的长度(这个范围的)

iResponseContentLength += Convert.ToInt32(alRequestedRangesend( _

iLoop) - alRequestedRangesBegin(iLoop)) + 1

If bMultipart Then

' 如果是多部分范围请求,计算出将发送的中间头信息的长度

iResponseContentLength += MULTIPART_BOUNDARY.Length

iResponseContentLength += objFile.ContentType.Length

iResponseContentLength += alRequestedRangesBegin(iLoop).ToString.Length

iResponseContentLength += alRequestedRangesend(iLoop).ToString.Length

iResponseContentLength += objFile.Length.ToString.Length

' 49是多部分下载中换行和其它必要的字符的长度

iResponseContentLength += 49

End If

Next iLoop

If bMultipart Then

' 如果是多部分范围请求,

' 我们还必须计算出将发送的最后一个中间头信息的长度

iResponseContentLength +=MULTIPART_BOUNDARY.Length

' 8 是破折号和换行符的长度

iResponseContentLength += 8

Else

' 不是多部分下载,因此我们必须说明初始HTTP头信息的响应范围

objResponse.AppendHeader( HTTP_HEADER_CONTENT_RANGE, "bytes " & _

alRequestedRangesBegin(0).ToString & "-" & _

alRequestedRangesend(0).ToString & "/" & _

objFile.Length.ToString)

'End If

' 范围响应

objResponse.StatusCode = 206 ' 局部响应

Else

' 这不是范围请求,或者被请求的范围实体ID与当前的实体ID不匹配,

' 因此开始新的下载

' 指明文件完成部分的大小等于内容的长度

iResponseContentLength =Convert.ToInt32(objFile.Length)

' 返回正常的OK状态

objResponse.StatusCode = 200

End If

' 接下来服务器必须发送几个重要的响应头信息,例如内容长度、Etag、和文件的内容类型:

' 把内容长度写入响应

objResponse.AppendHeader( HTTP_HEADER_CONTENT_LENGTH,iResponseContentLength.ToString)

' 把最后修改日期写入响应

objResponse.AppendHeader( HTTP_HEADER_LAST_MODIFIED,objFile.LastWriteTimeUTC.ToString("r"))

' 告诉客户端软件我们接受了范围请求

objResponse.AppendHeader( HTTP_HEADER_ACCEPT_RANGES,HTTP_HEADER_ACCEPT_RANGES_BYTES)

' 把文件的实体标签写入响应(用引号括起来)

objResponse.AppendHeader(HTTP_HEADER_ENTITY_TAG, """" & objFile.EntityTag & """")

' 把内容类型写入响应

If bMultipart Then

' 多部分消息有这种特殊的类型

' 在例子中文件实际的mime类型在以后才写入响应

objResponse.ContentType = MULTIPART_CONTENTTYPE

Else

' 单个部分消息拥有的文件内容类型

objResponse.ContentType = objFile.ContentType

End If

下载所需要的一切都准备好了,可以开始下载文件了。你将使用FileStream对象从文件中读取字节块。把FileInformation实例objFile的State属性设置为fsDownloadInProgress。只要客户端保持连接,服务器就从文件中读取字节块并发送给客户端。对于多部分下载,这段代码会发送特定的头信息。如果客户端中断连接,服务器就把文件状态设置为fsDownloadBroken。如果服务器完成了被请求范围的发送过程,它会把状态设置为fsDownloadFinished(见下载代码)。

FileInformation辅助类

在ZIPHandler部分中你会发现,FileInformation是一个辅助类,它封装了下载状态信息(例如下载中、中断等等)。

为了建立FileInformation的实例,你需要把被请求文件的路径传递给该类的构造函数:

Public Sub New(ByVal sPath As String)

m_objFile = New System.IO.FileInfo(sPath)

End Sub

FileInformation使用System.IO.FileInfo对象来获取文件的信息,这些信息是作为该对象的属性暴露的(例如文件是否存在、文件全名、大小等等)。这个类还暴露了一个DownloadState枚举,它描述了下载请求的多种状态:

Enum DownloadState

' Clear:没有下载过程,文件可能在维护

fsClear = 1

' Locked:动态建立的文件不能被更改

fsLocked = 2

' In Progress:文件被锁定了,下载过程正在进行

fsDownloadInProgress = 6

' Broken:文件被锁定了,下载过程正在进行,但是被取消了

fsDownloadBroken = 10

' Finished:文件被锁定了,下载过程完成了

fsDownloadFinished = 18

End Enum

FileInformation还提供了EntityTag属性值。示例代码中的这个值是硬编码的,这是由于示例代码只使用了一个下载文件,并且该文件不会被改变,但是对于实际应用程序来说,你会提供多个文件,甚至于动态地建立文件,你的代码必须为每个文件提供一个唯一的EntityTag值。此外,每次改变或修改该文件的时候,这个值也必须改变。这使客户端软件能够验证它们已经下载的字节块是否仍然是最新的。下面是示例代码中返回硬编码EntityTag值的部分:

Public ReadOnly Property EntityTag() As String

' EntityTag用于对客户端的初始(200)响应,以及来自客户端的恢复请求

Get

' 为文件建立唯一的字符串。

' 注意,只要文件没有发生改变,该唯一码就必须保留。

' 但是,如果文件的确改变了或者被修改了,这个码必须改变。

Return "MyExampleFileID"

End Get

[1] [2] 下一页

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有