Web 拒绝了多部分请求 API

Multipart request rejected by Web API

我正在尝试使用 HttpWebRequest 向 Web API 发送多部分请求。我发送的请求具有以下格式:

----------636194206488346738
Content-Disposition: form-data; name="file"; filename="A.png"
Content-Type:application/octet-stream
Content-Transfer-Encoding: binary
{Binary data in here}
----------636194206488346738--
{new line at the end}

并且请求配置如下:

Content-Type:"multipart/form-data; boundary=----------636194206488346738
Method: POST
Keep-Alive: True

向网络发送请求时 API 我得到了 Invalid end of stream error。但是,我尝试将流转换为文本以查看实际数据,它与我在上面添加的示例相匹配。

然而,当我使用 WebClient 并出于相同目的调用 UploadFile 方法时,我可以成功地将文件上传到 API 而没有任何问题提示我的方法是错误的,如下所示。

我的常数:

Boundary = DateTime.Now.Ticks.ToString();
ContentType = "multipart/form-data; boundary=" + BoundaryDelimiter + Boundary;
BeginContent = System.Text.Encoding.UTF8.GetBytes("\r\n" + BoundaryDelimiter + Boundary + "\r\n");
EndContent = System.Text.Encoding.UTF8.GetBytes("\r\n" + BoundaryDelimiter + Boundary + "--\r\n");

格式化表单数据的方法:

private Byte[] FormDataFormat(String name, String fileName, String contentType)
        => System.Text.Encoding.UTF8.GetBytes(String.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type:{2}\r\nContent-Transfer-Encoding: binary\r\n\r\n", name, fileName, contentType));

正在将文件附加到流:

Stream = new MemoryStream();
foreach (var i in files) {
    var tempEncode = FormDataFormat("file", i, "application/octet-stream");
    var file = System.IO.File.ReadAllBytes(i); // Files are supposed to be small.
    Stream.Write(BeginContent, 0, BeginContent.Length);
    Stream.Write(tempEncode, 0, tempEncode.Length);
    Stream.Write(file, 0, file.Length);
    ContentLenght += BeginContent.Length + tempEncode.Length + file.Length;
}
Stream.Write(EndContent, 0, EndContent.Length);
ContentLenght += EndContent.Length;

正在创建请求:

public HttpWebRequest Request(String method) {
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
        request.ContentType = ContentType;
        request.KeepAlive = true;
        request.Method = method;
        request.ContentLength = ContentLenght;
        Stream.Seek(0, SeekOrigin.Begin);
        Stream.CopyTo(request.GetRequestStream());
        Stream.Dispose();
        return request;
    }

你没有在你的问题中显示 BoundaryDelimiter 变量声明,但为了这个答案的目的,我假设它是这样定义的:

BoundaryDelimiter = "---------------------"

现在您的代码的问题是您在计算边界分隔符时遗漏了几个破折号 (--) 以符合 RFC2388.

所以代替:

BeginContent = System.Text.Encoding.UTF8.GetBytes("\r\n" + BoundaryDelimiter + Boundary + "\r\n");
EndContent = System.Text.Encoding.UTF8.GetBytes("\r\n" + BoundaryDelimiter + Boundary + "--\r\n");

你需要这个:

BeginContent = System.Text.Encoding.UTF8.GetBytes("\r\n" + BoundaryDelimiter + "--" + Boundary + "\r\n");
EndContent = System.Text.Encoding.UTF8.GetBytes("\r\n" + BoundaryDelimiter + "--" + Boundary + "--\r\n");

请注意我添加到您的开始和结束内容边界分隔符的额外 --

查看示例provided here:

Content-Type: multipart/form-data; boundary=AaB03x

--AaB03x
Content-Disposition: form-data; name="submit-name"

Larry
--AaB03x
Content-Disposition: form-data; name="files"; filename="file1.txt"
Content-Type: text/plain

... contents of file1.txt ...
--AaB03x--

注意边界如何等于 AaB03x 但分隔符实际上是 --AaB03x 当然结束分隔符是 --AaB03x--.

作为旁注,您可以删除 ContentLenght 变量(顺便说一句,您拼错了:-))并删除此行:

request.ContentLength = ContentLenght

这将简化您的代码,因为 HttpWebRequest class 将根据您写入请求流的字节数自动填充 Content-Length header。

也就是说,我建议您使用 HttpClient class 而不是 HttpWebRequest,因为它已经具有 built-in 正确编码此类内容的能力。它肯定会使您的代码更具可读性,因为您不必担心边界、定界符和内容长度。