6

我有一个 AJAX 表单,用户可以在其中上传 CSV 文件。这些文件相当小,服务器端处理将花费比实际文件上传更多的时间。尽管如此,上传可能仍需要一两秒钟,具体取决于文件大小和连接速度。此外,用户知道服务器端操作是成功还是失败也很重要。

现在我想区分“上传文件”和“等待响应”,以便向用户显示相应的消息/指示图标等。

我正在使用 jQuery's $.ajax,我可以在其中指定一个complete()-callback。但这在收到服务器的响应之前不会触发。据我所知,没有requestComplete()-callback。

那么,简而言之,有没有办法检测一个 AJAX 请求是否已经完全发送到服务器,即使服务器还没有响应呢?

如果可能的话,我宁愿不诉诸服务器和客户端推送(WebSockets 或 Comet 等)上的异步处理。(服务器运行 PHP)。

4

3 回答 3

4

请参阅会话上传进度功能。

启用后,PHP 将在用户会话中存储上传进度信息。然后,您可以通过执行一些 ajax 拉取来获取这些数据。

或者,APC 也有类似的功能

于 2013-05-24T16:43:39.787 回答
3

arnaud576875 的答案适用于实际的文件上传(您说这可能需要几秒钟也可能不需要几秒钟)。您可能需要这两种方法。一般来说,PHP 中没有用于跟踪脚本中的进度的机制 - PHP 既不知道它的百分比,也不一定会在结束之前将任何数据返回给调用者(即使它这样做了,您的 JS 也不会收到部分输出)。

执行此操作的标准方法是让浏览器不断轮询服务器以获取脚本的进度。上传是单独的,因此您还需要找到它并合并这两个数字 - 这需要估计每个任务(上传、处理)需要多长时间以及一些良好的代数技能。

在您的脚本中,您需要确定完成的百分比(如果您有一个大的 foreach 循环,这很容易)并将其存储在某处(数据库、文件、APC)。您还需要一种识别用户的方法(user_id 和/或从 javascript 传递一个随机数作为 ID)。

然后,您的轮询脚本(例如每 2 秒)将通过传递唯一 ID 来获取脚本进度的此编号。

于 2013-05-24T16:56:47.257 回答
2

根据您评论中的要求,这里是对我的评论的更完整解释。

至于跟踪上传进度,这是可能的,无需编写特定的服务器端代码来支持跟踪上传进度。正如您所提到的,我说的onprogress是 XMLHttpRequest level 2 提供的事件。它很容易使用。看看我刚才提到的链接的一小部分:

var oReq = new XMLHttpRequest();

oReq.addEventListener("progress", updateProgress, false);

oReq.open();

oReq.send(something);

// progress on transfers from the server to the client (downloads)
function updateProgress (oEvent) {
  if (oEvent.lengthComputable) {
    var percentComplete = oEvent.loaded / oEvent.total;
    // ...
  } else {
    // Unable to compute progress information since the total size is unknown
  }
}

至于您问题中提到的其他项目:

我想区分“上传文件”和“等待响应”,以便向用户显示相应的消息/指示图标等。

这在理论上当然是可能的。我在我维护的跨浏览器上传库Fine Uploader中所做的是等到最后一个字节已发送(根据我的进度处理程序),然后在 UI 中的文件旁边添加一条消息,例如“处理。 ……”。我假设,随着最后一个字节的发送,服务器正在对文件执行一些任务,我现在只是在等待响应。

我说这在理论上是可以检测到的,但实际上不能跨浏览器检测。为什么?我在Fine Uploader Github 存储库中的一个案例中对此发表了评论。我将在此处包含我的全部评论:

我注意到 Firefox 在收到服务器的响应之前不会触发它的最后一个进度事件,这有点令人沮丧。提交了一个Firefox 问题来跟踪此“问题”。

听起来 Firefox 可能实际上是在遵循 XHR V2 规范的字母,而 Chrome 则在坚持规范的“精神”。Chrome 的实现会导致在“发送”最后一个字节后触发最后一个进度事件,这是大多数人所期望的,但这可能只是违反规范。不确定 IE10 做了什么,因为我还没有研究过。一位 FF 开发人员在 w3.org 上打开了一个帖子,要求澄清一下。

Chromium 开发人员认为“预期”行为实际上是 webkit 细节,而不是特定于 Chrome。这表明 Safari 和 Chrome 表现出相同的行为,我已经验证了这一点。听起来好像有必要调整规范以允许 webkit 的行为成为预期的行为(根据规范的字母)。

请注意,我没有使用“loadend”事件来确定浏览器何时完成发送最后一个字节。在处理“进度”事件通知时,我只是将“加载”值与“总”值进行比较。如果这两个值相等,我声明文件“完全发送”。根据规范,我应该能够做到这一点(我认为),因为“loadend”事件只是在最后一个“progress”事件之后触发。有关更多详细信息,请参阅有关ProgressEvent的规范。

总而言之,这在 Chrome 和 Safari 中运行良好,但在 FireFox 中运行良好。我不记得这是否适用于 IE10。我不记得了,因为我很少使用 IE。在 Firefox 中,进度指示器会在接近 99% 左右时卡住,直到收到响应。

请注意,所有这些进度跟踪只有在用户代理支持文件 API 的情况下才能实现。这忽略了 IE9 和更早版本。对于非文件 API 浏览器,有几个选项:

  1. 建立某种约定,涉及客户端和服务器可以理解的 GET 请求。客户端会定期向服务器发送 GET 请求,服务器必须响应文件进度。FYI Fine Uploader 有一个预定的功能请求来进一步研究这个问题,尽管我对这种方法并不是很着迷。
  2. 另一种选择,看起来更好一点,但可能有更多限制(因为它取决于应用程序服务器)是使用 nginx 中的 UploadProgress 模块(如果您不熟悉,则发音为 Engine-X)。有人告诉我 Apache 有一个类似的模块,但我无法找到任何文档(尽管我根本没有研究这么多)。Fine Uploader 也有 [对此的功能请求 ( https://github.com/Widen/fine-uploader/issues/506 ),我也将在不久的将来进行调查。

希望这能回答你的问题。

于 2013-05-27T15:24:00.813 回答