.NET 4.7.1客户端与服务端通过REST传输byte[]问题求助
客户端报错修复与优化实现
问题根源
报错Status Code: 500, ReasonPhrase: 'could not find expected boundary'的核心原因:
- 错误地将内部文件内容的ContentType设置为
multipart/form-data,这个类型属于外层MultipartFormDataContent,文件本身应该用二进制流类型 ContentDisposition使用了attachment,表单上传场景下必须用form-data,且要指定name属性供服务端识别- Accept头无需复杂设置,只需指定服务端支持的响应类型即可,比如接受任意类型
*/*
修正后的客户端代码
HttpClient client = new HttpClient(); // 清除原有Accept头,添加可接受的响应类型 client.DefaultRequestHeaders.Accept.Clear(); // 若服务端返回Location(URI),可直接用*/*表示接受任意响应格式 client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*")); using (var content = new MultipartFormDataContent()) { var fileContent = new ByteArrayContent(bytes); // 文件内容设置为二进制流类型 fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream"); // 使用form-data类型的ContentDisposition,指定name(需与服务端解析时对应) fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") { Name = "uploadFile", FileName = "My.dat" }; content.Add(fileContent); var response = await client.PostAsync(url, content); response.EnsureSuccessStatusCode(); return response.Headers.Location; }
服务端文件接收实现
核心逻辑
通过HttpListenerRequest解析multipart/form-data请求体,提取指定name的文件内容,写入目标文件。需手动处理请求边界,定位文件内容区域。
可靠实现代码
public async Task ReceiveFile(HttpListenerRequest request, string saveFilePath) { if (!request.HasEntityBody) return; // 验证请求类型并提取边界 var contentType = request.ContentType; if (!contentType.StartsWith("multipart/form-data")) throw new InvalidOperationException("请求格式错误,仅支持multipart/form-data"); var boundaryPart = contentType.Split(';') .FirstOrDefault(p => p.Trim().StartsWith("boundary="))? .Split('=')[1].Trim(); if (string.IsNullOrEmpty(boundaryPart)) throw new InvalidOperationException("无法解析请求边界"); var boundary = $"--{boundaryPart}"; var boundaryBytes = request.ContentEncoding.GetBytes(boundary); var endBoundaryBytes = request.ContentEncoding.GetBytes($"{boundary}--"); using (var requestStream = request.InputStream) using (var fileStream = new FileStream(saveFilePath, FileMode.Create, FileAccess.Write, FileShare.None, 4096, true)) { byte[] buffer = new byte[8192]; int bytesRead; bool isFileContent = false; bool isEnd = false; while ((bytesRead = await requestStream.ReadAsync(buffer, 0, buffer.Length)) > 0 && !isEnd) { if (!isFileContent) { // 定位到目标文件的form-data块 var chunk = request.ContentEncoding.GetString(buffer, 0, bytesRead); if (chunk.Contains($"name=\"uploadFile\"") && chunk.Contains("filename=\"")) { // 跳过块头,定位到文件内容起始位置 var contentStart = chunk.IndexOf(Environment.NewLine + Environment.NewLine); if (contentStart != -1) { contentStart += 2 * Environment.NewLine.Length; var remaining = bytesRead - contentStart; await fileStream.WriteAsync(buffer, contentStart, remaining); isFileContent = true; } } } else { // 检查是否到达文件块结束边界 var chunk = request.ContentEncoding.GetString(buffer, 0, bytesRead); var boundaryIndex = chunk.IndexOf(boundary); if (boundaryIndex != -1) { // 写入边界前的有效内容 await fileStream.WriteAsync(buffer, 0, boundaryIndex); isEnd = true; } else { await fileStream.WriteAsync(buffer, 0, bytesRead); } } } } }
注意事项
- 代码中
name="uploadFile"需与客户端设置的Name属性完全一致 - 建议根据实际场景调整缓冲区大小(当前为8192字节),优化大文件写入性能
- 可添加异常捕获与日志记录,增强稳定性
内容的提问来源于stack exchange,提问作者Jim C
相关产品推荐
相关产品推荐

