fix(wxapi): 修复上传素材文件接口不支持 Unicode 文件名的问题

This commit is contained in:
Fu Diwei 2022-04-26 14:18:44 +08:00
parent 34dbf3b4be
commit 3b0e1b73cd
8 changed files with 55 additions and 77 deletions

View File

@ -354,14 +354,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
.CreateRequest(request, HttpMethod.Post, "card", "invoice", "platform", "setpdf")
.SetQueryParam("access_token", request.AccessToken);
string boundary = "--BOUNDARY--" + DateTimeOffset.Now.Ticks.ToString("x");
using var httpContent = new MultipartFormDataContent(boundary);
using var fileContent = new ByteArrayContent(request.FileBytes ?? Array.Empty<byte>());
httpContent.Add(fileContent, "\"pdf\"", "\"invoice.pdf\"");
httpContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data; boundary=" + boundary);
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/pdf");
fileContent.Headers.ContentLength = request.FileBytes?.Length;
using var httpContent = Utilities.FileHttpContentBuilder.Build(fileName: "invoice.pdf", fileBytes: request.FileBytes, fileContentType: "application/pdf", formDataName: "pdf");
return await client.SendRequestAsync<Models.CardInvoicePlatformSetPdfResponse>(flurlReq, httpContent: httpContent, cancellationToken: cancellationToken);
}

View File

@ -387,16 +387,8 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
.CreateRequest(request, HttpMethod.Post, "cgi-bin", "component", "uploadprivacyextfile")
.SetQueryParam("access_token", request.AccessToken);
string boundary = "--BOUNDARY--" + DateTimeOffset.Now.Ticks.ToString("x");
using var fileContent = new ByteArrayContent(request.FileBytes ?? Array.Empty<byte>());
using var httpContent = new MultipartFormDataContent(boundary);
httpContent.Add(fileContent, "\"file\"", $"\"{HttpUtility.UrlEncode(request.FileName)}\"");
httpContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data; boundary=" + boundary);
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(request.FileContentType);
fileContent.Headers.ContentLength = request.FileBytes?.Length;
using var httpContent = Utilities.FileHttpContentBuilder.Build(fileName: request.FileName, fileBytes: request.FileBytes, fileContentType: request.FileContentType, formDataName: "file");
return await client.SendRequestAsync<Models.CgibinComponentUploadPrivacyExtraFileResponse>(flurlReq, httpContent: httpContent, cancellationToken: cancellationToken);
}
}
}

View File

@ -84,20 +84,11 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
.SetQueryParam("access_token", request.AccessToken)
.SetQueryParam("type", request.Type);
string boundary = "--BOUNDARY--" + DateTimeOffset.Now.Ticks.ToString("x");
using var fileContent = new ByteArrayContent(request.FileBytes ?? Array.Empty<byte>());
using var descContent = new ByteArrayContent(Encoding.UTF8.GetBytes(client.JsonSerializer.Serialize(request)));
using var httpContent = new MultipartFormDataContent(boundary);
httpContent.Add(fileContent, "\"media\"", $"\"{HttpUtility.UrlEncode(request.FileName)}\"");
httpContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data; boundary=" + boundary);
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(request.FileContentType);
fileContent.Headers.ContentLength = request.FileBytes?.Length;
using var httpContent = Utilities.FileHttpContentBuilder.Build(fileName: request.FileName, fileBytes: request.FileBytes, fileContentType: request.FileContentType, formDataName: "media");
if (TYPE_VIDEO.Equals(request.Type))
{
httpContent.Add(descContent, "\"description\"");
httpContent.Add(new ByteArrayContent(Encoding.UTF8.GetBytes(client.JsonSerializer.Serialize(request))), "\"description\"");
}
return await client.SendRequestAsync<Models.CgibinMaterialAddMaterialResponse>(flurlReq, httpContent: httpContent, cancellationToken: cancellationToken);
}

View File

@ -62,14 +62,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
.SetQueryParam("access_token", request.AccessToken)
.SetQueryParam("type", request.Type);
string boundary = "--BOUNDARY--" + DateTimeOffset.Now.Ticks.ToString("x");
using var fileContent = new ByteArrayContent(request.FileBytes ?? Array.Empty<byte>());
using var httpContent = new MultipartFormDataContent(boundary);
httpContent.Add(fileContent, "\"media\"", $"\"{HttpUtility.UrlEncode(request.FileName)}\"");
httpContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data; boundary=" + boundary);
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(request.FileContentType);
fileContent.Headers.ContentLength = request.FileBytes?.Length;
using var httpContent = Utilities.FileHttpContentBuilder.Build(fileName: request.FileName, fileBytes: request.FileBytes, fileContentType: request.FileContentType, formDataName: "media");
return await client.SendRequestAsync<Models.CgibinMediaUploadResponse>(flurlReq, httpContent: httpContent, cancellationToken: cancellationToken);
}
@ -121,14 +114,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
.CreateRequest(request, HttpMethod.Post, "cgi-bin", "media", "uploadimg")
.SetQueryParam("access_token", request.AccessToken);
string boundary = "--BOUNDARY--" + DateTimeOffset.Now.Ticks.ToString("x");
using var fileContent = new ByteArrayContent(request.FileBytes ?? Array.Empty<byte>());
using var httpContent = new MultipartFormDataContent(boundary);
httpContent.Add(fileContent, "\"media\"", $"\"{HttpUtility.UrlEncode(request.FileName)}\"");
httpContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data; boundary=" + boundary);
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(request.FileContentType);
fileContent.Headers.ContentLength = request.FileBytes?.Length;
using var httpContent = Utilities.FileHttpContentBuilder.Build(fileName: request.FileName, fileBytes: request.FileBytes, fileContentType: request.FileContentType, formDataName: "media");
return await client.SendRequestAsync<Models.CgibinMediaUploadImageResponse>(flurlReq, httpContent: httpContent, cancellationToken: cancellationToken);
}

View File

@ -93,14 +93,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
.SetQueryParam("access_token", request.AccessToken)
.SetQueryParam("kf_account", request.KfAccount);
string boundary = "--BOUNDARY--" + DateTimeOffset.Now.Ticks.ToString("x");
using var fileContent = new ByteArrayContent(request.HeadImageFileBytes ?? Array.Empty<byte>());
using var httpContent = new MultipartFormDataContent(boundary);
httpContent.Add(fileContent, "\"media\"", "\"image.jpg\"");
httpContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data; boundary=" + boundary);
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
fileContent.Headers.ContentLength = request.HeadImageFileBytes?.Length;
using var httpContent = Utilities.FileHttpContentBuilder.Build(fileName: "image.jpg", fileBytes: request.HeadImageFileBytes, fileContentType: "image/jpeg", formDataName: "media");
return await client.SendRequestAsync<Models.CustomServiceKfAccountUploadHeadImageResponse>(flurlReq, httpContent: httpContent, cancellationToken: cancellationToken);
}

View File

@ -39,14 +39,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
{
flurlReq.SetQueryParam("upload_type", 0);
string boundary = "--BOUNDARY--" + DateTimeOffset.Now.Ticks.ToString("x");
using var httpContent = new MultipartFormDataContent(boundary);
using var fileContent = new ByteArrayContent(request.ImageFileBytes ?? Array.Empty<byte>());
httpContent.Add(fileContent, "\"media\"", "\"image.png\"");
httpContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data; boundary=" + boundary);
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/png");
fileContent.Headers.ContentLength = request.ImageFileBytes?.Length;
using var httpContent = Utilities.FileHttpContentBuilder.Build(fileName: "image.png", fileBytes: request.ImageFileBytes, fileContentType: "image/png", formDataName: "media");
return await client.SendRequestAsync<Models.ShopImageUploadResponse>(flurlReq, httpContent: httpContent, cancellationToken: cancellationToken);
}
}

View File

@ -390,14 +390,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
.CreateRequest(request, HttpMethod.Post, "wxa", "img_sec_check")
.SetQueryParam("access_token", request.AccessToken);
string boundary = "--BOUNDARY--" + DateTimeOffset.Now.Ticks.ToString("x");
using var fileContent = new ByteArrayContent(request.FileBytes ?? Array.Empty<byte>());
using var httpContent = new MultipartFormDataContent(boundary);
httpContent.Add(fileContent, "\"media\"", "\"image.png\"");
httpContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data; boundary=" + boundary);
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/png");
fileContent.Headers.ContentLength = request.FileBytes?.Length;
using var httpContent = Utilities.FileHttpContentBuilder.Build(fileName: "image.png", fileBytes: request.FileBytes, fileContentType: "image/png", formDataName: "media");
return await client.SendRequestAsync<Models.WxaImageSecurityCheckResponse>(flurlReq, httpContent: httpContent, cancellationToken: cancellationToken);
}
@ -781,15 +774,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
.CreateRequest(request, HttpMethod.Post, "wxa", "imagesearch")
.SetQueryParam("access_token", request.AccessToken);
string boundary = "--BOUNDARY--" + DateTimeOffset.Now.Ticks.ToString("x");
using var httpContent = new MultipartFormDataContent(boundary);
using var fileContent = new ByteArrayContent(request.ImageFileBytes ?? Array.Empty<byte>());
httpContent.Add(fileContent, "\"img\"", "\"image.png\"");
httpContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data; boundary=" + boundary);
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/png");
fileContent.Headers.ContentLength = request.ImageFileBytes?.Length;
using var httpContent = Utilities.FileHttpContentBuilder.Build(fileName: "image.png", fileBytes: request.ImageFileBytes, fileContentType: "image/png", formDataName: "img");
return await client.SendRequestAsync<Models.WxaImageSearchResponse>(flurlReq, httpContent: httpContent, cancellationToken: cancellationToken);
}

View File

@ -0,0 +1,45 @@
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
namespace SKIT.FlurlHttpClient.Wechat.Api.Utilities
{
internal static class FileHttpContentBuilder
{
public static MultipartFormDataContent Build(string fileName, byte[] fileBytes, string fileContentType, string formDataName)
{
return Build(fileName: fileName, fileBytes: fileBytes, fileContentType: fileContentType, formDataName: formDataName, (_) => { });
}
public static MultipartFormDataContent Build(string fileName, byte[] fileBytes, string fileContentType, string formDataName, Action<HttpContent> configureFileHttpContent)
{
if (fileName == null) throw new ArgumentNullException(nameof(fileName));
if (formDataName == null) throw new ArgumentNullException(nameof(formDataName));
if (configureFileHttpContent == null) throw new ArgumentNullException(nameof(configureFileHttpContent));
fileName = fileName.Replace("\"", "");
fileBytes = fileBytes ?? Array.Empty<byte>();
fileContentType = string.IsNullOrEmpty(fileContentType) ? "application/octet-stream" : fileContentType;
formDataName = formDataName.Replace("\"", "");
// HACKED: 默认不支持 Unicode 文件名 https://github.com/dotnet/runtime/issues/22996
byte[] bytesFileName = Encoding.UTF8.GetBytes(fileName);
char[] bytesHackedFileName = new char[bytesFileName.Length];
Array.Copy(bytesFileName, 0, bytesHackedFileName, 0, bytesFileName.Length);
string hackedFileName = new string(bytesHackedFileName);
ByteArrayContent fileContent = new ByteArrayContent(fileBytes);
fileContent.Headers.ContentDisposition = ContentDispositionHeaderValue.Parse($"form-data; name=\"{formDataName}\"; filename=\"{hackedFileName}\"");
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(fileContentType);
fileContent.Headers.ContentLength = fileBytes.Length;
configureFileHttpContent(fileContent);
string boundary = "--BOUNDARY--" + DateTimeOffset.Now.Ticks.ToString("x");
MultipartFormDataContent httpContent = new MultipartFormDataContent(boundary);
httpContent.Headers.ContentType = MediaTypeHeaderValue.Parse($"multipart/form-data; boundary={boundary}");
httpContent.Add(fileContent);
return httpContent;
}
}
}