Web API

时间:2017-01-07 18:40:02

标签: asp.net-web-api httpwebrequest multipartform-data webrequest

我正在尝试使用HttpWebRequest向Web API发送Multipart请求。我发送的请求格式如下:

----------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

将请求发送到Web 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;
    }

1 个答案:

答案 0 :(得分:2)

您没有在问题中显示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类将根据您写入请求流的字节数自动填充Content-Length标头。

话虽如此,我建议您使用HttpClient类而不是HttpWebRequest,因为它已经具有内置功能,可以正确编码这类内容。它肯定会使您的代码更具可读性,因为您不必担心边界,分隔符和内容长度。