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


  在写 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"));访问地址 http://www.vlan9.com/net-protocol/x106968.html 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值