我正在开发一个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
会以某种方式影响这个过程吗?谷歌搜索引导我到https://github.com/caxap/jquery-safeform插件,但它的目的有点不同。
答案 0 :(得分:12)
这取决于您要向用户呈现的UI类型。您可以简单地降低服务器级别的超时,如果它无法及时完成响应,它将中止。但是,用户体验非常苛刻,因为他们只会得到一个通用的超时错误,甚至可能来自您的网站。 (他们必须点击或返回您的网站。)
如果您只想在经过一段时间后显示消息,则可以附加到表单的提交事件并使用setTimeout
显示警告或其他内容:
$('#MyForm').on('submit', function () {
setTimeout(30000, function () { // number is milliseconds
alert('Sorry this is taking so long.');
});
});
最后,如果有一些跟踪服务器端正在完成的操作进度的方法,您可以使用Web套接字或通过AJAX进行长轮询来提供进度条或某种状态更新。但是,这有点复杂,需要你做一些研究。
答案 1 :(得分:4)
有两种方法,我会写两个单独的答案。
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();
}
这些来源是对original article的修改。有related stackoverflow question。
答案 2 :(得分:3)
如何在等待响应太长的时候以一种回调的方式组织表单?
这是基于您的算法。您可以估算蛮力计算的时间,并在开始执行前显示结果。如果您开始处理,然后在花费太多时间时将其分解,那么它不是优化的解决方案!
更新:如果你不能像上面那样进行估算,至少要写一个asynch
控制器方法,当一个动作必须执行几个独立的长时间运行时这个方法很有用操作。请遵循:
OnBegin
表单选项的函数以调用timer asynch
控制器方法
包含一个计时器,当需要更多时停止处理
比??秒。答案 3 :(得分:0)
有两种方法,我会写两个单独的答案。
发送线程/ UI线程方法
你需要2个javascript“线程”。
发送帖子: 首先打开websocket并开始向服务器发送数据。在服务器端更新一些变量发送了多少数据以及剩余数量。
UI线程: 使用Ajax经常询问服务器(使用JSON格式的HTTP请求很好),发送了多少数据以及剩余多少数据并在javascript中呈现进度条。
Finnaly,当UI线程请求收到上传准备就绪的信息时,请使用jquery和show message或重定向页面删除进度条。
使用这种方法,您可以轻松显示发送字节,估计剩余时间,上传速度。
所以每个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);
答案 4 :(得分:0)
您可以从服务器端检查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!");
}
}