Multipart/form-data 请求 -- 上传 pdf 导致生成空白文件
Multipart/form-data request -- Uploading pdf is resulting in a blank file
我有一个 objective 可以将 pdf 文件从一台服务器发送到 REST API 来处理一些归档。我正在使用 .NET Core 3.1 和 RestEase API library 来帮助进行一些抽象。
我有一个简单的控制台应用程序,每天在特定时间运行。相关代码如下:
using System;
using System.Linq;
using System.Threading.Tasks;
using RestEase;
namespace CandidateUploadFile
{
class Program
{
static async Task Main(string[] args)
{
try
{
var apiClientBuilder = new ApiClientBuilder<ITestApi>();
var api = apiClientBuilder.GetApi("https://my.api.com");
var candidate = await api.GetCandidateByEmailAddress("tester@aol.com");
var fileName = "tester.pdf";
var fileBytesToUpload = await FileHelper.GetBytesFromFile($@"./{fileName}");
var result = await api.UploadCandidateFileAsync(fileBytesToUpload, candidate.Data.First().Id, fileName);
}
catch (Exception e)
{
System.Console.WriteLine(e);
}
}
}
}
apiClientBuilder
添加了一些 auth-header,就是这样。我确定那一点不相关。
ITestApi
看起来像这样:
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Models;
using RestEase;
namespace CandidateUploadFile
{
public interface ITestApi : IApi
{
[Get("v1/candidates/{candidateId}")]
Task<Models.Response<Candidate>> GetCandidate([Path] string candidateId);
[Get("v1/candidates")]
Task<Models.Response<IEnumerable<Candidate>>> GetCandidateByEmailAddress([Query] string email);
[Get("v1/candidates")]
Task<Models.Response<IEnumerable<Candidate>>> GetCandidates();
[Post("v1/candidates/{candidateId}/files?perform_as=327d4d21-5cb0-4bc7-95f5-ae43aabc2db7")]
Task<string> UploadFileAsync([Path] string candidateId, [Body] HttpContent content);
[Get("v1/users")]
Task<Models.Response<IEnumerable<User>>> GetUsers();
}
}
这里真正相关的是UploadFileAsync
。
您会从 Program.Main
中注意到我没有明确调用 UploadFileAsync
。为了使用 multipart/form-data
请求上传 pdf,我改为调用一个基本包装 UploadFileAsync
的扩展方法。 This approach is what comes as a recommendation in the RestEase library docs.。该扩展方法如下所示:
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace CandidateUploadFile
{
public static class ApiExtension
{
public static async Task<string> UploadCandidateFileAsync(this ITestApi api, byte[] data, string candidateId, string fileName)
{
var content = new MultipartFormDataContent();
var fileContent = new ByteArrayContent(data);
fileContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "file",
FileName = fileName
};
content.Add(fileContent);
return await api.UploadFileAsync(candidateId, content);
}
}
}
那么当我的控制台应用程序执行时会发生什么:我将从上传端点获得成功响应,并且存档服务器上的文件已创建,但它是空白的。
知道 不会 在我发送 .txt 文件时发生这种情况可能很重要。 .txt 文件将保存为预期的内容。
任何见解都会有所帮助。我不知道从哪里开始。
谢谢!
这个问题是由于我在 GetBytesFromFile
静态辅助方法中所做的。
我的静态助手使用 UTF-8 编码对我上传的 .pdf 中的 二进制 内容进行编码。但是,它在我上传的 .txt 文件上运行良好,这是可以预料的。
经验教训:没有必要——也没有意义——在将二进制内容分配给 multipart/form-data 内容之前尝试对其进行编码。我只需要按原样 "pass-through" 二进制内容,或多或少。
我有一个 objective 可以将 pdf 文件从一台服务器发送到 REST API 来处理一些归档。我正在使用 .NET Core 3.1 和 RestEase API library 来帮助进行一些抽象。
我有一个简单的控制台应用程序,每天在特定时间运行。相关代码如下:
using System;
using System.Linq;
using System.Threading.Tasks;
using RestEase;
namespace CandidateUploadFile
{
class Program
{
static async Task Main(string[] args)
{
try
{
var apiClientBuilder = new ApiClientBuilder<ITestApi>();
var api = apiClientBuilder.GetApi("https://my.api.com");
var candidate = await api.GetCandidateByEmailAddress("tester@aol.com");
var fileName = "tester.pdf";
var fileBytesToUpload = await FileHelper.GetBytesFromFile($@"./{fileName}");
var result = await api.UploadCandidateFileAsync(fileBytesToUpload, candidate.Data.First().Id, fileName);
}
catch (Exception e)
{
System.Console.WriteLine(e);
}
}
}
}
apiClientBuilder
添加了一些 auth-header,就是这样。我确定那一点不相关。
ITestApi
看起来像这样:
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Models;
using RestEase;
namespace CandidateUploadFile
{
public interface ITestApi : IApi
{
[Get("v1/candidates/{candidateId}")]
Task<Models.Response<Candidate>> GetCandidate([Path] string candidateId);
[Get("v1/candidates")]
Task<Models.Response<IEnumerable<Candidate>>> GetCandidateByEmailAddress([Query] string email);
[Get("v1/candidates")]
Task<Models.Response<IEnumerable<Candidate>>> GetCandidates();
[Post("v1/candidates/{candidateId}/files?perform_as=327d4d21-5cb0-4bc7-95f5-ae43aabc2db7")]
Task<string> UploadFileAsync([Path] string candidateId, [Body] HttpContent content);
[Get("v1/users")]
Task<Models.Response<IEnumerable<User>>> GetUsers();
}
}
这里真正相关的是UploadFileAsync
。
您会从 Program.Main
中注意到我没有明确调用 UploadFileAsync
。为了使用 multipart/form-data
请求上传 pdf,我改为调用一个基本包装 UploadFileAsync
的扩展方法。 This approach is what comes as a recommendation in the RestEase library docs.。该扩展方法如下所示:
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace CandidateUploadFile
{
public static class ApiExtension
{
public static async Task<string> UploadCandidateFileAsync(this ITestApi api, byte[] data, string candidateId, string fileName)
{
var content = new MultipartFormDataContent();
var fileContent = new ByteArrayContent(data);
fileContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "file",
FileName = fileName
};
content.Add(fileContent);
return await api.UploadFileAsync(candidateId, content);
}
}
}
那么当我的控制台应用程序执行时会发生什么:我将从上传端点获得成功响应,并且存档服务器上的文件已创建,但它是空白的。
知道 不会 在我发送 .txt 文件时发生这种情况可能很重要。 .txt 文件将保存为预期的内容。
任何见解都会有所帮助。我不知道从哪里开始。
谢谢!
这个问题是由于我在 GetBytesFromFile
静态辅助方法中所做的。
我的静态助手使用 UTF-8 编码对我上传的 .pdf 中的 二进制 内容进行编码。但是,它在我上传的 .txt 文件上运行良好,这是可以预料的。
经验教训:没有必要——也没有意义——在将二进制内容分配给 multipart/form-data 内容之前尝试对其进行编码。我只需要按原样 "pass-through" 二进制内容,或多或少。