当用户关闭页面时,如何阻止服务器发送的事件脚本运行? PHP

Posted

技术标签:

【中文标题】当用户关闭页面时,如何阻止服务器发送的事件脚本运行? PHP【英文标题】:How can i stop a server sent event script from running when the user closes the page? PHP 【发布时间】:2015-03-04 09:37:04 【问题描述】:

我试图在 php 后端使用 SSE 向用户发送消息。

后端代码的功能部分看起来像-

<?php
set_time_limit(0);
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
ignore_user_abort(0);
@session_start();
    ob_start();
    echo "retry: 1000\n";

    ob_flush();
    flush();

    require_once 'sql_connection_class.php';
    require 'chatbox_class.php';

    $chatbox=new chatboxclass($_GET['friendid']);

    function recursivesenddata()
    global $chatbox;
    $jsonobj=$chatbox->jsonloadunreadmessages();

    //append json object


if($jsonobj!=-1)

>           echo "data:$jsonobj\n\n";
>           ob_flush();
>           flush();
>         else
>           //don't send anything   
>         
    



while(true)
      recursivesenddata();
      session_write_close();
      sleep(1);

    
?>

当用户关闭页面时,ignore_user_abort(0) 似乎没有做任何事情。

在 $chatbox->jsonloadunreadmessages() 中有一个函数应该只在页面打开时执行,它会更新 mysql 数据库中的内容。但是即使页面关闭,这个脚本也会继续在服务器上运行!

当用户关闭页面以退出无限循环时,服务器端是否有检查?

【问题讨论】:

为什么要做无限循环?据我了解,只有在有更新时才应调用代码。你如何发起服务器调用? 只要用户在页面上,我就需要它继续运行,我可以在 x 次睡眠后退出循环,如果没有更优雅的解决方案就发送重试跨度> 我在这里可能不正确,但你不能做一个 吗? 哦,抱歉,我没有指定这个 php 文件是使用 javascript 调用的,例如 =>var source = new EventSource("demo_sse.php");该脚本挂在服务器上,仅在有消息时才发送消息,因此是无限循环。但是一旦启动就无法从客户端阻止它:( 【参考方案1】:

应在连接套接字关闭后立即终止 PHP 脚本。如果用户关闭页面后脚本继续运行,则说明您的 Apache/PHP 配置存在严重问题。

当客户端显式调用EventSource.close()、由于网络问题导致连接丢失、客户端关闭页面或您的PHP脚本终止时,可能会发生套接字关闭。

ignore_user_abort(false) 什么都不做;这是默认行为(脚本在连接关闭时终止)。将true 作为参数传递会使您的脚本在连接中继续存在,但这不会解决您的问题。

您的retry: 1000 没有任何作用,因为您从不关闭服务器端的套接字。 当客户端激活EventSource 对象并仅在客户端请求(或网络出现故障)时终止时,应调用您的 PHP 脚本,因此任何初始数据库调整都应仅在每个聊天连接发生一次。这是假设客户端不做任何会关闭连接的事情。

顺便说一句,这会给服务器带来很大压力:在整个聊天期间,每个聊天客户端都会运行一个 PHP 进程,并且轮询周期太小了大约 10 倍(10 秒绰绰有余)。让客户端每 30 秒左右轮询一次新消息会减少浪费。

【讨论】:

您好,感谢您的回复。我的 Apache/PHP 配置肯定有问题,我在 xampp btw 上测试代码。它到了当我关闭 sse 脚本并在 phpmyadmin 中手动将一行插入 sql 时,该行会自动更新,就好像 sse 仍在运行一样,并且只有当我断开并重新连接 xampp 的 Apache 和 MySQL 时,该行停止更新。重试 1000 只是放在那里,所以当传输过程中发生意外错误时,重试将是 1 秒,而不是默认的 3 秒。 另外,30 秒对于聊天应用程序来说并不是很实时。如果每次发生数据库调整时都需要调用重试,这与 ajax 长轮询有何不同?我只是在我的 while 循环中添加了一个条件,如果没有发送任何内容并调用重试,则使其在 30 秒后超时,尽管我必须在聊天类中重写很多代码才能成为解决方案。抱歉听起来很业余,我对 php 和服务器端的东西很陌生 在你的情况下,长轮询对我来说似乎是最好的解决方案。至于 30 秒的延迟,如果您的客户是无法忍受挫折的小孩,您可以延迟 10 秒,但恕我直言,这肯定会极大地浪费带宽、计算能力和电力。【参考方案2】:

ignore_user_abort() 在 IIS 系统上被忽略,您的配置可能会阻止它。

尝试在你的while循环中使用connection_aborted():

while ( connection_aborted() == 0 ) 
    recursivesenddata();
    session_write_close();
    sleep(1);

【讨论】:

感谢您的回复,即使关闭选项卡,connection_aborted() 似乎也会继续返回 0,我已经更改了 php.ini 文件上的 ignore_user_abort= Off 没有运气。

以上是关于当用户关闭页面时,如何阻止服务器发送的事件脚本运行? PHP的主要内容,如果未能解决你的问题,请参考以下文章

PHP,暂停脚本执行,直到另一个正在运行的脚本发出事件信号?

如何关闭跨站点脚本 (XSS) 筛选器

Angular 5 - 当用户关闭浏览器窗口时如何进行 API 调用?

屏幕关闭时,Android 10 会阻止网络请求和 GPS 呼叫

当应用程序在android上关闭时如何阻止重新启动服务?

Web 关闭页面时发送 Ajax 请求 —— sendBeacon