【问题标题】:XmlHttpRequest doesn't terminate request processingXmlHttpRequest 不会终止请求处理
【发布时间】:2014-02-10 05:20:24
【问题描述】:

我已经使用 XMLHttprequest 实现了长轮询机制。我的问题是浏览器关闭后,服务器端进程继续运行,并没有关闭。

网络服务器是httpd apache,进程是php脚本。

我确实希望 php 脚本在浏览器关闭后关闭。

我发现 php 不会发现连接关闭,除非它尝试将数据输出回浏览器。 这是一个问题,因为它会损害最小化带宽使用的目标。

客户端脚本,使用 onreadystatechange 来尝试读取部分数据,而无需每次通信都需要新的 XMLHttprequest。 在整个响应完成之前,某些浏览器将不允许读取部分数据:

<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"></meta>
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript">
  $(document).ready(NewReq);

  var mode = 0;
  function NewReq() {
    var Req = new XMLHttpRequest();
    var url = 'a.php';
    if (mode) {
      url += '?mode=' + mode;
    }
    Req.open('GET', url);
    Req.onreadystatechange = function(event) {
      var handler = ReadyState[this.readyState];
      if (typeof handler == 'function') {
        handler(this);
      }
    };
    inc_mycookie();
    Req.send();
  }

  var ReadyState = [
    //'NotInit', 'ReqRec', 'ConEst'
    null , null, null,
    partial // 'Proccessing'
    ,
    complete //'Finishied'
  ];

  function partial(Req) { //'Proc'
    if (mode == 1) {
      return;
    }
    try {
      var strings = Req.response.split(';');
      strings.pop();
      var data = JSON.parse(strings.pop());
      $('#message').text(data);
      mode = 2;
    }
    catch (e) {
      $('#message').text(e.message);
      mode = 1;
    }
    return;
  }

  function complete(Req) {
    var last = $('#message').text();
    $('#output').text(last);
    NewReq();  
  }

  function inc_mycookie() {
    var matches = document.cookie.match(/(?:^|;)mine=([^;]+);?/);
    if (matches) {
      var inc = parseInt(matches[1]) + 1;
      document.cookie = 'mine=' + inc;
    }
  }

</script>
</head>
<body>
<h3> output </h3>
<div id="output"></div>
<h3> partial </h3>
<div id="message"></div>
</body>
</html>

这里是 php 脚本(apache 有“php_value output_buffering Off”):

<?php
  header('Content-type: application/json');
  if (!isset($_COOKIE['mine'])) {
    setcookie('mine', 23);
    $_COOKIE['mine'] = 23;
  }
  $mode = isset($_GET['mode']) ? $_GET['mode'] : 1;
  print json_encode('test_' . $_COOKIE['mine']) . ';';
  if ($mode == 2 ) {
    $iter = 8; 
    while($iter) {
      sleep(2);
      $iter--;
      error_log('a.php:' . $iter);
      // if i remove this line, then erro_log will continue to show even when browser is closed
      print json_encode('test_' . $_COOKIE['mine'] . '_' . $iter) . ';';
    }
  }
?>

在浏览器支持部分响应的情况下,伤害也不算太大。

但是如果浏览器要求整个响应完成,那么损害将是长轮询的完全妥协,这意味着每 5 秒重复一次请求。

【问题讨论】:

  • 你目前的代码是什么?
  • 我添加了代码,发现php必须尝试将数据输出回客户端才能发现连接已中止
  • 我完成了问题的最终描述

标签: php apache xmlhttprequest


【解决方案1】:

尽管这已经快 5 年了,考虑一下

XMLHTTPRequest.abort()

问题中的 javascript 需要通过以下方式重新设计:

  1. Req设为全局变量,这样
  2. Req.abort() 可以被调用,在(例如)
  3. window.addEventListener('unload', function() { Req.abort(); })

这样关闭页面可能会导致客户端终止与服务器的连接。

【讨论】:

    【解决方案2】:

    一种可能的解决方案是添加间隔:

    <?php
    $iter = 200; 
    while($iter) {
      sleep(2);
      $iter--;
      error_log('a.php:' . $iter);
      if (update_exist()) {
        print json_encode('test_' . $_COOKIE['mine'] . '_' . $iter) . ';';
      }
      else if (($iter-200)%20 == 0) { // 180, 160, 140 ... 40, 20, 0
        print json_encode('check connection : ' . $iter) . ';';
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-02-06
      • 2011-06-11
      • 1970-01-01
      • 2011-09-13
      • 2018-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多