使用C# HttpClient上传含非ASCII文件名文件的异常求助
问题分析与解决方案
核心原因
你遇到的问题确实和文件名的编码方式直接相关:.NET 原生的MultipartFormDataContent在自动生成Content-Disposition头时,默认采用ISO-8859-1编码处理文件名,这会导致俄语等非ASCII字符被错误编码,服务器无法解析;而Postman、JavaScript则默认使用UTF-8编码,或遵循RFC 5987标准传递文件名,所以能正常工作。
之前用Uri.EscapeDataString()或HttpUtility.UrlEncode()无效的原因是:MultipartFormDataContent.Add()方法会忽略你传入的编码后的文件名,重新用默认编码生成Content-Disposition头。
解决方法
手动构建Content-Disposition头(推荐)
绕过MultipartFormDataContent的自动编码逻辑,直接给StreamContent设置符合UTF-8标准的Content-Disposition头,同时添加RFC 5987格式的filename*字段(兼容绝大多数现代服务器):
HttpClient client = new HttpClient(); var content = new MultipartFormDataContent(); string filePath = "C:/path/to/file/файл.pdf"; var stream = new StreamContent(File.OpenRead(filePath)); stream.Headers.ContentType = new MediaTypeHeaderValue("application/pdf"); string fileName = Path.GetFileName(filePath); // 构造符合标准的Content-Disposition头 var disposition = new ContentDispositionHeaderValue("form-data") { Name = "\"file\"", // form字段名必须用双引号包裹 FileName = $"\"{fileName}\"", // 兼容旧版服务器的UTF-8文件名 FileNameStar = $"utf-8''{Uri.EscapeDataString(fileName)}" // RFC 5987标准格式,优先被现代服务器识别 }; stream.Headers.ContentDisposition = disposition; content.Add(stream); var response = await client.PostAsync("https://example.com/upload", content);
额外注意事项
- 服务器端兼容性:确保服务器支持解析
filename*字段(主流框架如ASP.NET Core、Spring Boot都已支持);如果服务器仅支持旧版filename字段,只需保留FileName属性并确保服务器用UTF-8解析头。 - 引号的必要性:
Name和FileName的值必须用双引号包裹,否则部分服务器会解析失败(比如把文件名截断到第一个空格)。 - 避免重复编码:手动设置头时,不要重复对文件名编码,
Uri.EscapeDataString()仅用于FileNameStar部分。
内容的提问来源于stack exchange,提问作者Kamil Ibadov
相关产品推荐
相关产品推荐

