Подтвердить что ты не робот

Поймать слишком длинную форму представления

Я разрабатываю HTML-страницу, которая имеет простую форму HTML (ничего особенного), отправленную кнопкой. Существует пара ситуаций, когда форма отправляется, и ответ приходит слишком долго (если когда-либо действительно возвращается). Как я могу организовать форму так, как она вызывает какой-либо обратный вызов, когда ожидание ответа слишком велико? Мы могли бы показать какое-то уведомление для пользователя, указав, что наш сервер перегружен в этой ситуации.

Вот запрос, который отправляется по форме:

POST http://example.com/search HTTP/1.1
Host: example.com
Proxy-Connection: keep-alive
Content-Length: 83
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: http://example.com
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Referer: http://example.com/
Accept-Encoding: gzip, deflate
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: [cookie definition omitted]

[form data omitted]

Является ли Proxy-Connection: keep-alive каким-то образом влиять на процесс? Googling привел меня к https://github.com/caxap/jquery-safeform плагину, но это для немного другой цели.

4b9b3361

Ответ 1

Это зависит от того, какой тип пользовательского интерфейса вы хотите представить пользователю. Вы можете просто снизить тайм-аут на уровне сервера и, если он не сможет завершить ответ вовремя, он прервется. Тем не менее, пользовательский интерфейс довольно суровый, так как он просто получит общую ошибку таймаута, которая, вероятно, даже не будет с вашего сайта. (Им нужно будет щелкнуть или вернуться, чтобы вернуться на ваш сайт.)

Если вам просто нужно отобразить сообщение по прошествии определенного времени, вы можете прикрепить к событию отправки формы и использовать setTimeout для отображения предупреждения или чего-то еще:

$('#MyForm').on('submit', function () {
    setTimeout(30000, function () { // number is milliseconds
        alert('Sorry this is taking so long.');
    });
});

Наконец, если есть какой-то способ отслеживания выполнения действия, который выполняется на стороне сервера, вы можете использовать что-то вроде веб-сокетов или длительный опрос через AJAX, чтобы предоставить индикатор выполнения или статусное обновление какого-либо рода. Это немного сложнее, и вам потребуются некоторые исследования с вашей стороны.

Ответ 2

Есть два подхода, я напишу два отдельных ответа.

Достижение прогресса XMLHttpRequest  (для современных браузеров)

Просто отправьте данные и прочитайте результаты загрузки из XMLHttpRequest:

//-------------upload ------------------


var lastProgressIndex = -1;


//is the file api available in this browser
//only override *if* available.
if (new XMLHttpRequest().upload) {
    $("#upload-files").click(function () {       
        upload_files($("#files-to-upload")[0].files, lastProgressIndex++);
        return false;
    });
    $("#files-to-upload").change(function () {
        upload_files($("#files-to-upload")[0].files, lastProgressIndex++);
        return false;
    });
    $("#upload-files").hide();
}
function resetFormElement(elem) {
    elem.wrap('<form>').closest('form').get(0).reset();
    elem.unwrap();
}

function clear_upload() {
    //https://stackoverflow.com/questions/1043957/clearing-input-type-file-using-jquery
    var upload = $("#files-to-upload");
    //upload.replaceWith(upload = upload.clone(true));
    resetFormElement(upload);
}

//accepts the input.files parameter
function upload_files(filelist) {
    if (typeof filelist !== "undefined") {
        for (var i = 0, l = filelist.length; i < l; i++) {
            upload_file(filelist[i], lastProgressIndex++);
        }
    }
    clear_upload();
}

//each file upload produces a unique POST
function upload_file(file, index) {

    //TODO - vytvor progress bar podle indexu
    $("#progresscontainer").append('<div id="progressbar' + index + '" class="progressbar"><div id="progresslabel' + index + '" class="progressbarlabel"></div></div>')

    var progressBarSelector = "#progressbar" + index;
    var progressLabelSelector = "#progresslabel" + index;
    var fileName = file.name;

    var xhr = new XMLHttpRequest();

    xhr.upload.addEventListener("progress", function (evt) {
        if (evt.lengthComputable) {
            //update the progress bar

            var percent = Math.floor((evt.loaded / evt.total) * 100) + "%";

            //TODO http://www.binaryintellect.net/articles/859d32c8-945d-4e5d-8c89-775388598f62.aspx                  

            $(progressBarSelector).css({
                width: percent
            });
            $(progressLabelSelector).html(fileName + ' ' + percent);
        }
    }, false);

    // File uploaded
    xhr.addEventListener("load", function () {
        $(progressLabelSelector).html(fileName + " uploaded");

        AddImageToGallery(GetFilenameWithoutExt(fileName));

        $(progressBarSelector).fadeOut(500, function () {
            $(progressBarSelector).remove();
        });
    }, false);

    var guid = $("#Identification").val();
    xhr.open("post", "/uploadurl/uploadfile/" + guid, true);

    // Set appropriate headers
    // We're going to use these in the UploadFile method
    // To determine what is being uploaded.
    xhr.setRequestHeader("Content-Type", "multipart/form-data");
    xhr.setRequestHeader("X-File-Name", file.name);
    xhr.setRequestHeader("X-File-Size", file.size);
    xhr.setRequestHeader("X-File-Type", file.type);

    // Send the file
    xhr.send(file);
}

И серверная часть:

private UploadedFile[] RetrieveFileFromRequest()
{
    List<UploadedFile> uploadedFiles = new List<UploadedFile>();


    if (Request.Files.Count > 0)
    { //they're uploading the old way

        for (int i = 0; i < Request.Files.Count; i++)
        {
            var file = Request.Files[0];
            string contentType = file.ContentType;
            string filename = file.FileName;

            UploadedFile uploadedFile = SaveUploadedFile(file.InputStream, file.ContentLength, filename, contentType);

            uploadedFiles.Add(uploadedFile);
        }
    }
    else if (Request.ContentLength > 0)
    {
        string filename = Request.Headers["X-File-Name"];
        string contentType = Request.Headers["X-File-Type"];

        UploadedFile uploadedFile = SaveUploadedFile(Request.InputStream, Request.ContentLength, filename, contentType);
        uploadedFiles.Add(uploadedFile);
    }

    return uploadedFiles.ToArray();
}

Эти источники являются модификацией оригинальной статьи . Существует fooobar.com/questions/313204/....

Ответ 3

Как я могу организовать форму так, как она вызывает какой-либо обратный вызов, когда ожидание ответа слишком велико?

Это основано на вашем алгоритме. Вы можете оценить время как вычисление грубой силы и показать результат до начала выполнения. Это не оптимизированное решение, если вы начнете обработку, а затем сломаете его, когда потрачено слишком много времени!

Обновить. Если вы не можете оценить, как указано выше, по крайней мере, напишите метод контроллера asynch, который полезен, когда действие должно выполнить несколько независимых длительных операций. Следуйте этому:

  • Напишите форму Ajax с ненавязчивый-ajax
  • Определите функцию для формы формы OnBegin для вызова timer
  • Событие тайм-аут тайм-аута покажет пользователю еще одну вещь.
  • Напишите метод управления asynch для операции, которая содержит таймер, чтобы прекратить обработку, когда требуется больше чем?? секунд.

Ответ 4

Есть два подхода, я напишу два отдельных ответа.

Отправка потока/поток пользовательского интерфейса

Вам понадобятся два "потока" javascript.

Отправка потока:  С первым открытым websocket и началом отправки данных на сервер. На стороне сервера обновите некоторую переменную, сколько данных было отправлено и сколько осталось.

поток пользовательского интерфейса:  Часто задавать сервер Ajax (HTTP-запрос с JSON-форматом в порядке), сколько данных было отправлено и сколько осталось и отобразить прогресс-панель в javascript.

Finnaly, когда запрос потока пользовательского интерфейса получает информацию о том, что загрузка готова, удалите панель прогресса с jquery и покажите сообщение или страницу переадресации.

При таком подходе вы можете легко показать байты отправки, оставшееся время оценки, скорость загрузки.

Таким образом, каждый поток javascript имеет соответствующий протектор сервера. И оба потока сервера совместно используют структуру с dataSend и dataRemaining в зависимости от вашей серверной технологии.

Bellow Вы можете найти часть моего кода, который загружает несколько изображений и показывает предварительный просмотр после окончания:

intervalID = window.setInterval(function() 
{
    var request = new Sys.Net.WebRequest();
    request.set_url('UploadProgress.ashx?DJUploadStatus=' + token + '&ts=' + new Date().getTime());
    request.set_httpVerb('GET');
    request.add_completed(function(executor) {

        //  the progress is returned as xml
        var e = executor.get_xml().documentElement;
        var empty = e.getAttribute('empty');

        if (!empty) 
        {
            //  extract the attributes I am interested in
            var percent = e.getAttribute('progress');
            var file = e.getAttribute('file');
            var kbs = Math.round(parseInt(e.getAttribute('bytes')) / 1024);
            var size = Math.round(parseInt(e.getAttribute('size')) / 1024);

            //  update the progressbar to the new value
            progressBar.set_percentage(percent);

            //  upadte the message
            updateMessage('info', 'Uploading ' + file + ' ... ' + kbs + ' of ' + size + ' KB');

            if (percent == 100)
            {
                //  clear the interval
                window.clearInterval(intervalID);
            }
        }
    });

    //  invoke the request
    request.invoke();

}, 1000);

Ответ 5

Вы можете проверить исключение WebTimeout на стороне сервера, а затем использовать SignalR для активного отправки сообщений тайм-аута обратно на клиентскую сторону:

var request = (HttpWebRequest)WebRequest.Create("http://www.your_third_parties_page.com");
request.Timeout = 1000; //Timeout after 1000 ms

try
{
    using (var stream = request.GetResponse().GetResponseStream())
    using (var reader = new StreamReader(stream))
    {
         Console.WriteLine(reader.ReadToEnd());
    }
}
catch (WebException ex)
{
    //Check for timeout exception
    if (ex.Status == WebExceptionStatus.Timeout)
    {
         //If timeout then send SignalR ajax message to inform the clients...
         var context = GlobalHost.ConnectionManager.GetHubContext<YourHub>();
         context.Clients.All.addNewMessageToPage("This method has been processing too long!");
    }
}

Подробнее как настроить SignalR для asp.net здесь