C# WebClient参照Python requests向Trello API上传带MIME类型文件咨询
问题根源
你当前使用的 WebClient.UploadValues 仅支持普通表单编码格式的键值对提交,无法构造上传文件需要的 multipart/form-data 格式请求,因此Trello无法正确识别你传递的文件、文件名和MIME类型。另外你将base64解码后的二进制图片转成ASCII字符串的操作会直接损坏文件内容,直接保留解码后的字节数组即可。
方案1:基于WebClient的兼容实现
using Newtonsoft.Json; using System; using System.IO; using System.Net; using System.Text; namespace RescoTrello { class Program { static void Main(string[] args) { string key = "xxxx"; string token = "yyyy"; string trelloCardID = "zzzz"; string url = $"https://api.trello.com/1/cards/{trelloCardID}/attachments?key={key}&token={token}"; // 读取并解码base64文件内容,直接保留字节数组不要转字符串 string base64Encoded = File.ReadAllText("C:/file.txt"); byte[] fileBytes = Convert.FromBase64String(base64Encoded); string fileName = "testName.png"; string mimeType = "image/png"; // 构造multipart/form-data请求边界 string boundary = "----" + DateTime.Now.Ticks.ToString("x"); byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n"); using (WebClient client = new WebClient()) { client.Headers.Add("Content-Type", "multipart/form-data; boundary=" + boundary); using (MemoryStream ms = new MemoryStream()) { // 写入文件字段头 ms.Write(boundaryBytes, 0, boundaryBytes.Length); string fileHeader = $"Content-Disposition: form-data; name=\"file\"; filename=\"{fileName}\"\r\nContent-Type: {mimeType}\r\n\r\n"; byte[] fileHeaderBytes = Encoding.UTF8.GetBytes(fileHeader); ms.Write(fileHeaderBytes, 0, fileHeaderBytes.Length); // 写入文件二进制内容 ms.Write(fileBytes, 0, fileBytes.Length); // 写入请求结束边界 byte[] endBoundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n"); ms.Write(endBoundaryBytes, 0, endBoundaryBytes.Length); try { byte[] responseBytes = client.UploadData(url, "POST", ms.ToArray()); Rootobject resultJson = JsonConvert.DeserializeObject<Rootobject>(Encoding.UTF8.GetString(responseBytes)); Console.WriteLine(resultJson.id); } catch (WebException e) { Console.WriteLine(e.Message); } } } } } }
方案2:更推荐的HttpClient实现(.NET Framework 4.5+ 及所有.NET Core/.NET 版本支持)
WebClient是已经被官方标记为过时的旧API,使用HttpClient代码更简洁,也不需要手动构造请求格式:
using Newtonsoft.Json; using System; using System.IO; using System.Net.Http; using System.Net.Http.Headers; using System.Text; namespace RescoTrello { class Program { // HttpClient建议全局静态复用,不要每次请求新建 private static readonly HttpClient _httpClient = new HttpClient(); static void Main(string[] args) { string key = "xxxx"; string token = "yyyy"; string trelloCardID = "zzzz"; string url = $"https://api.trello.com/1/cards/{trelloCardID}/attachments"; string base64Encoded = File.ReadAllText("C:/file.txt"); byte[] fileBytes = Convert.FromBase64String(base64Encoded); string fileName = "testName.png"; string mimeType = "image/png"; using (var content = new MultipartFormDataContent()) { // 传递公共参数 content.Add(new StringContent(key), "key"); content.Add(new StringContent(token), "token"); content.Add(new StringContent(fileName), "name"); // 传递文件内容、文件名、MIME类型 var fileContent = new ByteArrayContent(fileBytes); fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(mimeType); content.Add(fileContent, "file", fileName); try { var response = _httpClient.PostAsync(url, content).GetAwaiter().GetResult(); response.EnsureSuccessStatusCode(); string responseStr = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); Rootobject resultJson = JsonConvert.DeserializeObject<Rootobject>(responseStr); Console.WriteLine(resultJson.id); } catch (HttpRequestException e) { Console.WriteLine(e.Message); } } } } }
内容的提问来源于stack exchange,提问作者Kresten
相关产品推荐
相关产品推荐

