0

Я пытаюсь отправить запрос Multipart в веб-API с помощью HttpWebRequest. Запрос я посылаю имеет следующий формат:Многосторонний запрос отклонен веб-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; 
    } 

ответ

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, поскольку он уже имеет встроенные возможности для правильного кодирования такого рода материалов. Это, безусловно, сделает ваш код более читаемым, так как вам не придется беспокоиться о границах, разделителях и длинах контента.

+0

Я только что заметил, что моменты перед тем, как увидеть ваш ответ. :) – Arrrr

 Смежные вопросы

  • Нет связанных вопросов^_^