如何制作一个通过多部分表单数据发送 Base64 加密八位字节流的 http 客户端?

How can I make a http client that sends Base64 encrypted octet stream via Multipart form data?

上下文

我公司有一个 API 很难处理。我成功地使用 Postman 发出了一个 PUT 请求,现在我想使用一个简单的控制台应用程序在 C# 中构建相同的 http 请求。 这是邮递员要求:

第二个键必须完全这样命名。 entry Json 我可以通过文件或直接作为值使用。

这是headers:

唯一重要的是授权 Header.

问题

我不知道如何在 C# 中实际创建这个复杂的请求,因为我对这种语言还很陌生,找不到解决我的具体问题的方法。

我尝试使用 C# 和 RestSharp 中的普通 httpclient,但无法发出此请求。

这是我目前的情况:

{
  class Program
  {

    static readonly HttpClient client = new HttpClient();
    static async Task Main(string[] args)
    {
      using var multipart = new MultipartFormDataContent();
      var jsonBytes = JsonSerializer.SerializeToUtf8Bytes(new { Metadata = "abc" });
      // Need to add my json file or the json direct here somewhere

      // This is how the JSON looks like
      /*
            {
        "values": {
            "z1D_WorklogDetails": "very new workinfo 3",
            "z1D_View_Access": "Internal",
            "z1D Action": "MODIFY",
            "z2AF_Act_Attachment_1": "UID Liste.xlsx"
            }
        }
      */
      multipart.Add(new ByteArrayContent(jsonBytes), "entry");

      using var fs = File.OpenRead(@"C:\myFile.txt");
      multipart.Add(new StreamContent(fs), "attach-z2AF_Act_Attachment_1");

      multipart.Headers.Add("Authorization", "//my token here");

      using var resp = await client.PostAsync("**/entry/HPD:IncidentInterface/INC000001479529|INC000001479529", multipart);
      resp.EnsureSuccessStatusCode();
    }
  }
}

那么如何才能让这个复杂的请求像Postman中显示的on一样在C#中完全一样呢? API 管理员告诉我 attach-z2AF_Act_Attachment_1 中的附件必须经过 Base64 加密

任何对这个调用的实际作用感兴趣的人:

它向我们的工单系统 (BMC Remedy) 中的现有工单添加了一个新的工作日志,并且还向这个新的工作日志条目添加了一个附件。

非常感谢。

请查看下面的代码,请在您的环境中进行测试。

重点是您可以手动设置内容类型。

还有一点就是你设置的Authorization header错误。

    using System.Net.Http.Headers;
    using System.Net.Mime;
    using System.Security.Cryptography;
    using System.Text;
    using System.Text.Json;
    
    string url = "https://localhost/";
    string token = "token_here";
    
    //Prepare json data
    string json = JsonSerializer.Serialize(new { Metadata = "abc" });
    StringContent jsonContent = new StringContent(json, Encoding.UTF8, MediaTypeNames.Application.Json);
    
    StreamContent streamContent;
    
    bool base64 = false;
    //Prepare octet-stream data
    if (base64)
    {
        //For base-64 encoded message
        using FileStream inputFile = new FileStream(@"2.txt", FileMode.Open, FileAccess.Read, FileShare.None,
            bufferSize: 1024 * 1024, useAsync: true);
        using CryptoStream base64Stream = new CryptoStream(inputFile, new ToBase64Transform(), CryptoStreamMode.Read);
        streamContent = new StreamContent(base64Stream);
        streamContent.Headers.Add("Content-Type", MediaTypeNames.Application.Octet);
    
        await SendRequest(jsonContent, streamContent, url, token);
    }
    else
    {
        //For plain message
        using FileStream file = File.OpenRead("2.txt");
        streamContent = new StreamContent(file);
        streamContent.Headers.Add("Content-Type", MediaTypeNames.Application.Octet);
    
        await SendRequest(jsonContent, streamContent, url, token);
    }
    
    
    async Task SendRequest(StringContent stringContent, StreamContent streamContent, string url, string token)
    {
        // Add json and octet-stream to multipart content
        MultipartFormDataContent multipartContent = new MultipartFormDataContent();
        multipartContent.Add(stringContent, "entry");
        multipartContent.Add(streamContent, "attach-z2AF_Act_Attachment_1");
    
        //Create request
        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Put, url);
        //Here is the right setting of auth header value, sheme is on the left side
        request.Headers.Authorization = new AuthenticationHeaderValue("AR-JWT", token);
        request.Content = multipartContent;
    
        //Last step - sending request
        HttpClient http = new HttpClient();
        HttpResponseMessage resp = await http.SendAsync(request);
        resp.EnsureSuccessStatusCode();
    }

通过我的方法,我得到了这个请求:

Headers:
{
  "content-length": "6538",
  "authorization": "AR-JWT token_here",
  "content-type": "multipart/form-data; boundary=\"02600173-b9af-49f4-8591-e7edf2c0b397\""
}

Body:

--02600173-b9af-49f4-8591-e7edf2c0b397
Content-Type: application/json; charset=utf-8
Content-Disposition: form-data; name=entry

{"Metadata":"abc"}
--02600173-b9af-49f4-8591-e7edf2c0b397
Content-Type: application/octet-stream
Content-Disposition: form-data; name=attach-z2AF_Act_Attachment_1

OCTET DATA HERE

--02600173-b9af-49f4-8591-e7edf2c0b397--

正确吗?


更新:我制作了一个 base-64 编码版本的附件。 只需将 base64 设置为 true。

使用 base64 方法请求:

Headers:
{
  "content-length": "354",
  "authorization": "AR-JWT token_here",
  "content-type": "multipart/form-data; boundary=\"7572d1e8-7bd7-4f01-9c78-ce5b624faab3\""
}

Body:
--7572d1e8-7bd7-4f01-9c78-ce5b624faab3
Content-Type: application/json; charset=utf-8
Content-Disposition: form-data; name=entry

{"Metadata":"abc"}
--7572d1e8-7bd7-4f01-9c78-ce5b624faab3
Content-Type: application/octet-stream
Content-Disposition: form-data; name=attach-z2AF_Act_Attachment_1

MjIyMg==
--7572d1e8-7bd7-4f01-9c78-ce5b624faab3--