Возможно ли потоковое скачивание большого файла без добавления maxRequestLength в web.config? - PullRequest
0 голосов
/ 19 октября 2018
 ┌─────────┐      ┌─ ───────────┐      ┌───────────────────────┐
 │ Postman │ ───► │ Web API App │ ───► │ Save file to a folder │
 └─────────┘      └─────────────┘      └───────────────────────┘

Чтобы смоделировать, я передаю файл в Web API через почтальона, и API, наконец, сохраняет файл в папку.

Проблема - input.Read выбрасывает Maximum request length exceeded. исключение.

Вопрос - Могу ли я загрузить потоковый файл большого размера без добавления maxRequestLengthи maxAllowedContentLength в web.config?

Другими словами, можем ли мы обойтись без добавления этих настроек в web.config?

enter image description here

public class ServerController : ApiController
{
    public async Task<IHttpActionResult> Post()
    {
        // Hard-coded filename for testing
        string filePath = string.Format(@"C:\temp\{0:yyyy-MMM-dd_hh-mm-ss}.zip", DateTime.Now);

        int bufferSize = 4096;
        int bytesRead;
        byte[] buffer = new byte[bufferSize];

        using (Stream input = await Request.Content.ReadAsStreamAsync())
        using (Stream output = File.OpenWrite(filePath))
        {
            while ((bytesRead = input.Read(buffer, 0, bufferSize)) > 0)
            {
                output.Write(buffer, 0, bytesRead);
            }
        }

        return Ok();
    }
}

Ответы [ 2 ]

0 голосов
/ 19 октября 2018

Это сложно, но не невозможно.Идея: разрезать файл на куски на стороне клиента и отправить его по частям.На сервере объединяем куски.Это рабочий пример.

Клиент:

<input type="file" id="inFile" />
<button id="btnSend" type="button">Upload</button>
<script>
    document.getElementById('btnSend').addEventListener('click', function () {
        var chunkSize = 200; //small for test purpose. Set below limit
        var fu = document.getElementById('inFile');
        if (!fu.files) return;
        var reader = new FileReader();
        reader.onload = function () {
            var bytes = this.result.split('').map(function (b) { return b.charCodeAt(); });
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function () {
                if (this.readyState === 4 && this.status === 200) {
                    var b = bytes.splice(0, chunkSize);
                    if (b.length) {
                        //repeat until EOF
                        xhr.open('POST', 'img-upload.ashx', true);
                        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
                        xhr.send('fn=' + fu.files[0].name + '&bytes=' + b);
                    }
                }
            };
            xhr.open('POST', 'img-upload.ashx', true);
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); //required to use Request.Form on the server
            xhr.send('fn=' + fu.files[0].name + '&bytes=' + bytes.splice(0, chunkSize) + '&chunk=0'); //mark 1st chunk
        }
        reader.readAsBinaryString(fu.files[0]);
    });
</script>

Сервер:
Я использовал общий обработчик ASP.NET (.ashx)здесь.

using System;
using System.Web;
using System.Linq;

public class img_upload : IHttpHandler {

    public void ProcessRequest (HttpContext context) {
        string[] strBytes = ((string)context.Request.Form["bytes"]).Split(',');
        byte[] bytes = strBytes.Select(b => Convert.ToByte(b)).ToArray();
        string fileName = context.Server.MapPath("~/misc/img/" + (string)context.Request.Form["fn"]); //make sure the process has write permission
        System.IO.FileStream fs = null;
        if (context.Request.Form["chunk"] == "0")//first chunk
        {
            fs = new System.IO.FileStream(fileName, System.IO.FileMode.Create);
        }
        else
        {
            fs = new System.IO.FileStream(fileName, System.IO.FileMode.Append);
        }
        fs.Write(bytes, 0, bytes.Length);
        fs.Close();
        context.Response.ContentType = "text/plain"; //or whatever
        context.Response.Write("OK");//or whatever
    }

    public bool IsReusable {
        get {
            return false;
        }
    }
}
0 голосов
/ 19 октября 2018

вы не можете сделать это программно.Длина запроса обрабатывается HttpWorkerRequest до вызова фактического HttpHandler.Это означает, что универсальный обработчик или страница выполняется после того, как запрос попал на сервер и обработан соответствующим работником asp.net.

Вы не можете контролировать maxRequestLength в коде вашей страницы или HttpHandler!

Если вам нужно установить максимальную длину для конкретной страницы, вы можете сделать это следующим образом, используя тег:

<configuration>
  <location path="yourPage.aspx">
    <system.web>
      <httpRuntime maxRequestLength="2048576" executionTimeout="54000" />
    </system.web>
  </location>
</configuration>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...