分享
 
 
 

通过 HTTP POST 上传文件到服务器.

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

在写 ASP.NET 应用的时候, 往往会碰到客户端上传文件的情况,这个时候客户一般希望能够想 windows 应用一样, 能够选择文件夹, 浏览所要下载的文件,批量上传, 这个时候. 有几个特征:

1. 客户可以自由的浏览本地的文件夹, 选择多个文件同时上传.

2. 上传之前用户无法预知上传文件的数目.

3. 因为是 ASP.NET 应用, 客户端可能没有装 .NET Framework.

其实,我们知道.如果要跟 IE 端客户文件系统交互的话,代码必须在客户端执行. 这个时候我们可以写一个 Activex 控件来实现选择文件夹和上传.

一般我们常用两种方式往服务端上传文件

1. FTP , 可以调用一些现成的 FTP 组件, 在 VB 里面可以调用 Internet Transfer Control

2. HTTP , 使用 HTTP Post application/octet-stream 格式的字节流给服务端.

FTP 很容易实现,我们不予考虑,着重提一下HTTP 的方式.

我们在单个文件上传的时候,一般都有以下的代码:

<%@ Page Language="C#" AutoEventWireup="True" %>

<html>

<head>

<script runat="server">

void Button1_Click(object sender, EventArgs e)

{

// Get the HtmlInputFile control from the Controls collection

// of the PlaceHolder control.

HtmlInputFile file = (HtmlInputFile)Place.FindControl("File1");

// Make sure a file was submitted.

if (Text1.Value == "")

{

Span1.InnerHtml = "Error: you must enter a file name";

return;

}

// Save file to server.

if (file.PostedFile != null)

{

try

{

file.PostedFile.SaveAs("c:\\temp\\"+Text1.Value);

Span1.InnerHtml = "File uploaded successfully to " +

"<b>c:\\temp\\" + Text1.Value + "</b> on the Web server";

}

catch (Exception exc)

{

Span1.InnerHtml = "Error saving file <b>c:\\temp\\" +

Text1.Value + "</b><br>" + exc.ToString();

}

}

}

void Page_Load(object sender, EventArgs e)

{

// Create a new HtmlInputFile control.

HtmlInputFile file = new HtmlInputFile();

file.ID = "File1";

// Add the control to the Controls collection of the

// PlaceHolder control.

Place.Controls.Clear();

Place.Controls.Add(file);

}

</script>

</head>

<body>

<h3>HtmlInputFile Constructor Example</h3>

<form enctype="multipart/form-data" runat="server">

Specify the file to upload:

<asp:PlaceHolder id="Place" runat="server"/>

<p>

Save as file name (no path):

<input id="Text1"

type="text"

runat="server">

<p>

<span id=Span1

style="font: 8pt verdana;"

runat="server" />

<p>

<input type=button

id="Button1"

value="Upload"

OnServerClick="Button1_Click"

runat="server">

</form>

</body>

</html>

代码有两部分操作:

1. 客户端, 通过用户选择要上传的文件, post 到服务端,这个时候注意 Post 的不是一些普通的表单,而是一个octet-stream 格式的流.

2. 服务端, 如果服务端 是 ASP.NET 处理程序的话, Request 对象有一个 Files 熟悉个您, Files 里面会包含你上传的各个文件内容和文件信息.

你需要做的就是调用一下 File.Save ,把文件复制到你的服务器目录.

我们模拟一下这个过程:

对于客户端, 我们写一个 windows 应用程序.

主要是以下几行代码:

Dim wc As New System.Net.WebClient

wc.Credentials = New System.Net.NetworkCredential("username", "password", "domain")

wc.UploadFile("http://localhost/aspnet/UPloadFile/WebForm1.aspx", "c:\localfile.txt")

注意: 很多人用 UploadFile ,希望传两个参数,第一个是服务器文件存放的位置, 第二个是本地文件路径.

这个时候, 如果你改为wc.UploadFile("http://localhost/remotefile.txt", "c:\LocalFile.txt"), 一般会报错 405, “Methods are not allowed“, 错误有一点误导. 主要是告诉你 Remotefile.txt 无法处理你的 Post 方法. 而 IIS 的log 也会有类似的提示:

2004-08-13 03:37:57 127.0.0.1 POST /remotefile.txt - 80 - 127.0.0.1 - 405 0 1

所以这个时候明确一点, 服务端必须有一个文件能够处理这个post 过去的数据.

模拟服务端:

服务端就很简单了, 跟上传代码差不多.

新建一个 web form, html 代码如下.

<form id="Form1" encType="multipart/form-data" runat="server">

</form>

逻辑代码:

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

'在此处放置初始化页的用户代码

Dim b() As Byte = Request.BinaryRead(Request.ContentLength)

Dim fs As New System.IO.FileStream("c:\k.txt", IO.FileMode.Append) //把request 请求的数据dump 到一个文件中

Dim sw As New System.IO.BinaryWriter(fs)

sw.Write(b)

sw.Close()

fs.Close()

Request.Files(0).SaveAs("C:\t\" & Request.Files(0).FileName) //另存客户端传上来的文件

End Sub

运行这个程序. 你会发现客户端发过去的 请求,起始很有规则:

-----------------------8c64f47716481f0 //时间戳

Content-Disposition: form-data; name="file"; filename="a.txt" //文件名

Content-Type: application/octet-stream

//文件的内容

-----------------------8c64f47716481f0

这个是.NET 测试的一些结果. 起始我们看一下 WebClient.UploadFile , 他起始内部就是整理形成一个 request 流.以下是对 webclient.uploadFile 反编译后看到的结果.

public byte[] UploadFile(string address, string method, string fileName)

{

string text1;

string text2;

WebRequest request1;

string text3;

byte[] buffer1;

byte[] buffer2;

long num1;

byte[] buffer3;

int num2;

WebResponse response1;

byte[] buffer4;

DateTime time1;

long num3;

string[] textArray1;

FileStream stream1 = null;

try

{

fileName = Path.GetFullPath(fileName);

time1 = DateTime.Now;

num3 = time1.Ticks;

text1 = "---------------------" + num3.ToString("x");

if (this.m_headers == null)

{

this.m_headers = new WebHeaderCollection();

}

text2 = this.m_headers["Content-Type"];

if (text2 != null)

{

if (text2.ToLower(CultureInfo.InvariantCulture).StartsWith("multipart/"))

{

throw new WebException(SR.GetString("net_webclient_Multipart"));

}

}

else

{

text2 = "application/octet-stream";

}

this.m_headers["Content-Type"] = "multipart/form-data; boundary=" + text1;

this.m_responseHeaders = null;

stream1 = new FileStream(fileName, FileMode.Open, FileAccess.Read);

request1 = WebRequest.Create(this.GetUri(address));

request1.Credentials = this.Credentials;

this.CopyHeadersTo(request1);

request1.Method = method;

textArray1 = new string[7];

textArray1[0] = "--";

textArray1[1] = text1;

textArray1[2] = "\r\nContent-Disposition: form-data; name=\"file\"; filename=\"";

textArray1[3] = Path.GetFileName(fileName);

textArray1[4] = "\"\r\nContent-Type: ";

textArray1[5] = text2;

textArray1[6] = "\r\n\r\n";

text3 = string.Concat(textArray1);

buffer1 = Encoding.UTF8.GetBytes(text3);

buffer2 = Encoding.ASCII.GetBytes("\r\n--" + text1 + "\r\n");

num1 = 9223372036854775807;

try

{

num1 = stream1.Length;

request1.ContentLength = ((num1 + ((long) buffer1.Length)) + ((long) buffer2.Length));

}

catch

{

}

buffer3 = new byte[Math.Min(((int) 8192), ((int) num1))];

using (Stream stream2 = request1.GetRequestStream())

{

stream2.Write(buffer1, 0, buffer1.Length);

do

{

num2 = stream1.Read(buffer3, 0, buffer3.Length);

if (num2 != 0)

{

stream2.Write(buffer3, 0, num2);

}

}

while ((num2 != 0));

stream2.Write(buffer2, 0, buffer2.Length);

}

stream1.Close();

stream1 = null;

response1 = request1.GetResponse();

this.m_responseHeaders = response1.Headers;

return this.ResponseAsBytes(response1);

}

catch (Exception exception1)

{

if (stream1 != null)

{

stream1.Close();

stream1 = null;

}

if ((exception1 is WebException) || (exception1 is SecurityException))

{

throw;

}

throw new WebException(SR.GetString("net_webclient"), exception1);

}

return buffer4;

}

还是很容易看懂的.

如果写 Activex 的话, 在 VB 中可以调用 Internet Transfer 控件, 我们模拟发一个文件给服务端.

Private Sub Command1_Click()

Dim s As String

s = s & "-----------------------8c64f47716481f0" & vbCrLf

s = s & "Content-Disposition: form-data; name=""file""; filename=""a.txt""" & vbCrLf

s = s & "Content-Type: application/octet-stream" & vbCrLf & vbCrLf

s = s & "Hello , World" & vbCrLf

s = s & "-----------------------8c64f47716481f0"

Inet1.Execute "http://localhost/aspnet/UPloadFile/WebForm1.aspx", "POST", s

End Sub

这时候服务端就会收到一个文件.

需要说明的是:

仅仅为了说明 HTTP Post 的原理,没有考虑很多的代码细节.

使用的时候请做适当的调整.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
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- 王朝網路 版權所有