基于HttpListener与Mono的C#多部分表单文件上传处理问题
处理HttpListener下的multipart/form-data文件上传
核心处理思路
- 从请求的
Content-Type头中解析出分隔符(boundary),这是区分multipart各数据块的核心标记 - 读取完整请求流,按boundary分割数据块
- 跳过每个块的头部信息(直到出现连续空行),仅提取后续的文件内容
适配Mono环境的代码实现
using System; using System.IO; using System.Net; using System.Text; class FileUploadServer { static void Main(string[] args) { var listener = new HttpListener(); listener.Prefixes.Add("http://localhost:8080/upload/"); listener.Start(); Console.WriteLine("服务器启动,等待上传请求..."); while (true) { var context = listener.GetContext(); var request = context.Request; var response = context.Response; // 过滤非POST和非multipart请求 if (request.HttpMethod != "POST" || !request.ContentType.StartsWith("multipart/form-data")) { response.StatusCode = (int)HttpStatusCode.BadRequest; response.Close(); continue; } // 解析分隔符 var boundary = request.ContentType.Split(';')[1].Split('=')[1].Trim(); var boundaryBytes = Encoding.UTF8.GetBytes($"--{boundary}"); using (var reader = new BinaryReader(request.InputStream)) using (var outputFile = new FileStream("uploaded_content.dat", FileMode.Create)) { byte[] buffer = new byte[4096]; int bytesRead; bool skipHeader = true; while ((bytesRead = reader.Read(buffer, 0, buffer.Length)) > 0) { if (skipHeader) { // 查找头部结束标记:连续两个换行\r\n\r\n var contentStr = Encoding.UTF8.GetString(buffer, 0, bytesRead); var headerEndIdx = contentStr.IndexOf("\r\n\r\n"); if (headerEndIdx != -1) { // 写入头部之后的内容 var contentBytes = Encoding.UTF8.GetBytes(contentStr.Substring(headerEndIdx + 4)); outputFile.Write(contentBytes, 0, contentBytes.Length); skipHeader = false; } } else { // 检查是否到达结束分隔符,避免写入冗余内容 var boundaryPos = Array.IndexOf(buffer, boundaryBytes[0], 0, bytesRead); if (boundaryPos != -1 && boundaryPos + boundaryBytes.Length <= bytesRead) { bool isMatch = true; for (int i = 0; i < boundaryBytes.Length; i++) { if (buffer[boundaryPos + i] != boundaryBytes[i]) { isMatch = false; break; } } if (isMatch) { // 写入分隔符前的有效内容后退出循环 outputFile.Write(buffer, 0, boundaryPos); break; } } outputFile.Write(buffer, 0, bytesRead); } } } // 返回上传成功响应 var responseBytes = Encoding.UTF8.GetBytes("文件内容提取完成"); response.ContentLength64 = responseBytes.Length; response.OutputStream.Write(responseBytes, 0, responseBytes.Length); response.Close(); } } }
关键细节说明
- 分隔符处理:
Content-Type中的boundary不带前缀--,拼接时需手动添加 - 头部跳过逻辑:利用
\r\n\r\n作为头部与内容的分隔标记,确保只提取有效文件数据 - 字节流处理:用
BinaryReader操作原始字节流,避免编码转换问题,后续支持图片上传时无需修改核心逻辑 - 结束判断:检测到结束分隔符时立即停止写入,防止把分隔符、结尾标记等冗余内容写入文件
内容的提问来源于stack exchange,提问作者Pixel
相关产品推荐
相关产品推荐

