c#使用HttpWebRequest上传文件同时携带其他参数

本文介绍了一个使用C#实现的简单文件上传和接收的示例代码。该示例通过创建两个Handler程序,一个用于上传文件,另一个用于接收文件,并展示了如何构造HTTP POST请求来发送文件和额外的键值参数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个小程序参考了另一位博友的代码,做了稍许调整,创建的两个Handler程序,一个上传的ashx,一个接收的ashx

上传文件代码

public void ProcessRequest(HttpContext context)
		{
			//参考http://www.cnblogs.com/greenerycn/archive/2010/05/15/csharp_http_post.html
			string filePath = "d:\\apple4.jpg";
			string fileName = "apple4.jpg";
			string postURL = "http://192.168.1.11/testhandler/accfile.ashx";
			
			// 边界符
			var boundary = "---------------" + DateTime.Now.Ticks.ToString("x");
			var beginBoundary = Encoding.ASCII.GetBytes("--" + boundary + "\r\n");
			var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);

			// 最后的结束符
			var endBoundary = Encoding.ASCII.GetBytes("--" + boundary + "--\r\n");

			// 文件参数头
			const string filePartHeader =
				"Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n" +
				 "Content-Type: application/octet-stream\r\n\r\n";
			var fileHeader = string.Format(filePartHeader, "file", fileName);
			var fileHeaderBytes = Encoding.UTF8.GetBytes(fileHeader);

			// 开始拼数据
			var memStream = new MemoryStream();
			memStream.Write(beginBoundary, 0, beginBoundary.Length);

			// 文件数据
			memStream.Write(fileHeaderBytes, 0, fileHeaderBytes.Length);
			var buffer = new byte[1024];
			int bytesRead; // =0
			while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
			{
				memStream.Write(buffer, 0, bytesRead);
			}
			fileStream.Close();

			// Key-Value数据
			var stringKeyHeader = "\r\n--" + boundary +
								   "\r\nContent-Disposition: form-data; name=\"{0}\"" +
								   "\r\n\r\n{1}\r\n";

			Dictionary<string, string> stringDict = new Dictionary<string, string>();
			stringDict.Add("len", "500");
			stringDict.Add("wid", "300");
			foreach (byte[] formitembytes in from string key in stringDict.Keys
											 select string.Format(stringKeyHeader, key, stringDict[key])
												 into formitem
												 select Encoding.UTF8.GetBytes(formitem))
			{
				memStream.Write(formitembytes, 0, formitembytes.Length);
			}

			// 写入最后的结束边界符
			memStream.Write(endBoundary, 0, endBoundary.Length);

			//倒腾到tempBuffer?
			memStream.Position = 0;
			var tempBuffer = new byte[memStream.Length];
			memStream.Read(tempBuffer, 0, tempBuffer.Length);
			memStream.Close();

			// 创建webRequest并设置属性
			var webRequest = (HttpWebRequest)WebRequest.Create(postURL);
			webRequest.Method = "POST";
			webRequest.Timeout = 100000;
			webRequest.ContentType = "multipart/form-data; boundary=" + boundary;
			webRequest.ContentLength = tempBuffer.Length;

			var requestStream = webRequest.GetRequestStream();
			requestStream.Write(tempBuffer, 0, tempBuffer.Length);
			requestStream.Close();

			var httpWebResponse = (HttpWebResponse)webRequest.GetResponse();
			string responseContent;
			using (var httpStreamReader = new StreamReader(httpWebResponse.GetResponseStream(),Encoding.GetEncoding("utf-8")))
			{
				responseContent = httpStreamReader.ReadToEnd();
			}

			httpWebResponse.Close();
			webRequest.Abort();

			context.Response.ContentType = "text/plain";
			context.Response.Write(responseContent);
		}

接收文件

public void ProcessRequest(HttpContext context)
		{
			context.Response.ContentType = "text/plain";
			if (context.Request.Files.Count == 0)
			{
				context.Response.Write("No file");
				return;
			}

			HttpPostedFile f1 = context.Request.Files[0];
			System.Drawing.Image image = System.Drawing.Image.FromStream(f1.InputStream);
			image.Save("d:\\upload.jpg");
			
			string strPars="";
			foreach (var key in context.Request.Form.AllKeys)
			{
				string val = context.Request[key];
				strPars += "["+key + ":" + val + "] ";
			}

			image.Dispose();
			context.Response.Write("OK Get File:" + f1.FileName + " Pars:" + strPars);
		}



<think>我们正在处理用户的问题:如何在C#使用HttpWebRequest上传文件,并设置自定义请求头。 根据引用[2]和引用[3],我们知道上传文件需要使用multipart/form-data格式,并且需要构建符合该格式的请求体。 同时,引用[1]提供了设置自定义请求头的方法,但请注意,在HttpWebRequest中,我们是通过HttpWebRequest.Headers属性来设置请求头的。 步骤: 1. 创建HttpWebRequest对象,指定URL。 2. 设置请求方法为POST。 3. 设置自定义请求头(注意:有些标头不能直接设置,需要通过属性设置,如Content-Type,但multipart/form-data的Content-Type需要包含boundary,所以我们在构建请求体时设置)。 4. 构建multipart/form-data格式的请求体,包含文件和其他表单数据。 5. 将请求体写入请求流。 6. 获取响应。 注意:在设置请求头时,我们通常使用Headers集合,但Content-Type这个头在HttpWebRequest中是通过ContentType属性设置的。对于multipart/form-data,我们需要设置一个包含boundary的Content-Type。 另外,引用[3]提到multipart/form-data的好处是能够区分文件内容和表单值,因此我们需要生成一个boundary字符串来分隔各部分。 我们将编写一个示例方法,展示如何上传文件并设置自定义请求头(例如一个自定义的认证头)。 具体步骤: 1. 创建一个HttpWebRequest实例。 2. 设置Method为"POST"。 3. 设置自定义请求头(除了Content-Type以外的头,例如"X-API-Key")。 4. 构建请求体,包括文件数据和可能的其他表单字段。 5. 设置ContentType属性为"multipart/form-data; boundary=我们生成的boundary"。 6. 将请求体写入请求流。 7. 获取响应。 注意:在上传文件时,可能需要设置AllowWriteStreamBuffering为true(默认)或false,以避免内存溢出。但默认情况下,HttpWebRequest会缓冲请求流,对于大文件可能占用大量内存。我们可以考虑设置AllowWriteStreamBuffering为false,然后使用流式上传,但这里我们主要关注基本方法。 由于引用[2]中后台接口使用了HttpPostedFile,因此我们的请求格式需要匹配该接口(即表单中文件字段名为"file",以及其他参数)。 示例代码: 假设我们要上传一个文件同时传递两个额外的参数:name和params(注意:params是C#关键字,所以我们在实际代码中应避免使用,但这里为了匹配接口,我们使用字符串形式)。 另外,自定义请求头我们添加一个"Custom-Auth-Token"和一个"X-API-Version"(如引用[1]所示)。 但是注意:HttpWebRequest.Headers集合中不能设置某些标头(如Content-Type、Content-Length等),这些标头有专门的属性。因此,我们设置自定义头时,要避免这些受限标头。 我们开始编写代码:</think>### C# HttpWebRequest 文件上传及请求头设置指南 在 C#使用 `HttpWebRequest` 上传文件需要以下关键步骤: #### 1. **基础设置** ```csharp string url = "https://your-api-endpoint"; string filePath = @"C:\test.zip"; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Method = "POST"; // 设置自定义请求头(非受限标头) request.Headers.Add("X-API-Version", "2.3.1"); request.Headers.Add("Custom-Auth-Token", Guid.NewGuid().ToString()); ``` > 💡 注意:`Content-Type` 等受限标头需通过专用属性设置,直接添加会抛出异常[^1]。 #### 2. **构建 multipart/form-data 请求体** ```csharp string boundary = "----" + DateTime.Now.Ticks.ToString("x"); request.ContentType = $"multipart/form-data; boundary={boundary}"; using (Stream requestStream = request.GetRequestStream()) { // 添加表单字段 string formData = $"--{boundary}\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\nparamValue\r\n"; byte[] formBytes = Encoding.UTF8.GetBytes(formData); requestStream.Write(formBytes, 0, formBytes.Length); // 添加文件 string header = $"--{boundary}\r\nContent-Disposition: form-data; name=\"file\"; filename=\"{Path.GetFileName(filePath)}\"\r\nContent-Type: application/octet-stream\r\n\r\n"; byte[] headerBytes = Encoding.UTF8.GetBytes(header); requestStream.Write(headerBytes, 0, headerBytes.Length); using (FileStream fileStream = File.OpenRead(filePath)) { byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0) { requestStream.Write(buffer, 0, bytesRead); } } // 结束标记 byte[] footerBytes = Encoding.UTF8.GetBytes($"\r\n--{boundary}--\r\n"); requestStream.Write(footerBytes, 0, footerBytes.Length); } ``` #### 3. **处理服务器响应** ```csharp using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) using (Stream responseStream = response.GetResponseStream()) using (StreamReader reader = new StreamReader(responseStream)) { Console.WriteLine($"状态码: {response.StatusCode}"); Console.WriteLine($"响应内容: {reader.ReadToEnd()}"); } ``` #### 关键说明: 1. **Boundary 生成** `boundary` 是分隔表单字段和文件的唯一标记,需在 `Content-Type` 中声明并在请求体中作为分隔符使用[^3]。 2. **大文件处理优化** ```csharp // 禁用缓冲提升大文件上传性能 request.AllowWriteStreamBuffering = false; ``` 3. **表单字段格式** 每个字段需按格式构建: ``` --{boundary} Content-Disposition: form-data; name="字段名" 空行 字段值 ``` 4. **文件部分格式** ``` --{boundary} Content-Disposition: form-data; name="file"; filename="文件名" Content-Type: MIME类型 空行 文件二进制数据 ``` #### 服务端接收示例(ASP.NET) ```csharp // 引用[2]中的接收代码 public IHttpActionResult Post() { var file = HttpContext.Current.Request.Files[0]; string name = HttpContext.Current.Request["name"]; file.SaveAs(@"C:\uploads\received.zip"); return Ok("上传成功"); } ``` > ⚠️ 注意事项: > - 避免在请求头中使用 `Content-Length` 等受限标头 > - 二进制文件使用 `application/octet-stream` 类型 > - 确保 boundary 字符串在请求体中唯一且不包含文件内容中的字符
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值