在 C# 中使用 Content-Length 和 Range 的 HttpClient putAsync 请求

HttpClient putAsync request with Content-Length and Range in C#

需要开发C# HttpClient PUT请求上传图片。这是运行良好的 curl 请求。

curl --location --request PUT 'https://somewheretest.com/abcd/efgh' \
--header 'Content-Type: application/octet-stream' \
--header 'Range: bytes=0-99999' \
--header 'Content-Length: 100000' \
--data-binary '@D:\image.jpg'

我已经尝试使用 HttpClient 发送请求 PutAsync 并使用 MultipartFormDataContent,得到响应 Invalid Range。对于在 C# UWP 中请求将图像上传到服务器的有效方式的任何建议表示赞赏。

我遵循了一些方法。但只有 CURL 运行良好。所有其他人的代码回复 Invalid Range.

第一#

public static async Task<bool> fileUpload(string filePath, long fileSize)
{
    string url = "";

    try
    {
        string range = "bytes=0-" + (fileSize - 1).ToString();

        using (var client = new System.Net.Http.HttpClient())
        {
            //client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36");
            //client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/octet-stream");
            //client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Length", fileSize.ToString());
            //client.DefaultRequestHeaders.TryAddWithoutValidation("Range", range);
            
            Uri uri = new Uri(url);

            using (var content = new MultipartFormDataContent())
            {
                FileStream fs = File.OpenRead(filePath);
                var streamContent = new StreamContent(fs);

                //HttpContent contents = new StringContent(filePath);
                //streamContent.Headers.TryAddWithoutValidation("Content-Type", "application/octet-stream");
                //streamContent.Headers.TryAddWithoutValidation("Content-Length", fileSize.ToString());
                //streamContent.Headers.TryAddWithoutValidation("Range", range);

                //content.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");

                content.Add(new StringContent("Content-Type"), "application/octet-stream");
                content.Add(new StringContent("Range"), range);
                content.Add(new StringContent("Content-Length"), fileSize.ToString());
                content.Add(streamContent, "file", Path.GetFileName(filePath));

                using (var message = await client.PutAsync(uri, content))
                {
                    var input = await message.Content.ReadAsStringAsync();
                    //var result = JsonSerializer.Deserialize<FileUploadResult>(input);
                    Debug.WriteLine($"Response File Upload: {input}");

                    return true;
                }
            }
        }
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex.ToString());
        return false;
    }
}

第二#

public static async Task<bool> UploadMultipart(byte[] file, string filename, string url)
{
    string contentType = "application/octet-stream";
    var webClient = new WebClient();
    string boundary = "------------------------" + DateTime.Now.Ticks.ToString("x");
    webClient.Headers.Add("Content-Type", "multipart/form-data; boundary=" + boundary);
    var fileData = webClient.Encoding.GetString(file);
    var package = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"file\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n{3}\r\n--{0}--\r\n", boundary, filename, contentType, fileData);

    var nfile = webClient.Encoding.GetBytes(package);

    byte[] resp = webClient.UploadData(url, "PUT", nfile);

    return true;
}

第三#

public static async Task<bool> fileUpload(ValueSet issueToken, string filePath, byte[] fileInByte)
{
    int fileSize = fileInByte.Length;
    //string range = "bytes=0-" + (fileSize - 1).ToString();
    string url = "";

    var httpClient = new System.Net.Http.HttpClient();

    try
    {
        //StreamContent streamContent = new StreamContent(new FileStream(filePath, FileMode.Open, FileAccess.Read));
        StreamContent streamContent = new StreamContent(new MemoryStream(fileInByte));
        streamContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
        streamContent.Headers.ContentRange = new System.Net.Http.Headers.ContentRangeHeaderValue(0, fileSize - 1);
        streamContent.Headers.ContentLength = fileSize;

        using (var message = await httpClient.PutAsync(url, streamContent))
        {
            var input = await message.Content.ReadAsStringAsync();
            //var result = JsonSerializer.Deserialize<FileUploadResult>(input);
            Debug.WriteLine($"Response File Upload: {input}");

            return true;
        }
    }
    catch(Exception ex)
    {
        Debug.WriteLine(ex);
        return false;
    }
}

不工作的唯一原因,System.Net.Http.HttpClient 在我从 wireshark 获得的 UWP 中表现不同。另一个原因是服务器配置非常旧,不支持请求中的多部分。无论如何,这是我使用 Windows.Web.Http.HttpClient.

的解决方案
public static async Task<bool> fileUpload(ValueSet issueToken, string filePath, byte[] fileInByte)
{
    int fileSize = fileInByte.Length;
    string range = "bytes=0-" + (fileSize - 1).ToString();
    string url = "https://somewheretest.com/abcd/efgh";

    var httpClient = new Windows.Web.Http.HttpClient();
    httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Range", range);
    
    try
    {
        HttpStreamContent streamContent = new HttpStreamContent(new FileStream(filePath, FileMode.Open, FileAccess.Read));
        streamContent.Headers.ContentType = new HttpMediaTypeHeaderValue("application/octet-stream");
        
        using (var message = await httpClient.PutAsync(new Uri(url), streamContent))
        {
            var output = await message.Content.ToString();
            Debug.WriteLine($"Response File Upload: {output}");

            return true;
        }
    }
    catch(Exception ex)
    {
        Debug.WriteLine(ex);
        return false;
    }
}