诺亚方舟

沉淀

PHP实现服务端主动断开连接后继续执行任务

很多时候,对于前端的接口请求,我们只想执行“一半”的脚本,并不想后端完全执行完毕后再返回给前端,这样会给客户端带来不好的体验是响应太慢,这时候我们可以考虑一种做法,主动断开客户端的请求。

可以利用的是ignore_user_abort($boolen)这个函数。正常来说,在http请求中,服务端每次的输出缓冲池满了后便会触发客户端输出,这时候php会去检测当前的请求状态,如果状态正常,脚本继续运行,如果状态异常,则中断当前php脚本的运行。而ignore_user_abort($boolen)这个函数,如果$boolen值设置为true时,php会忽略连接的异常状态,把脚本执行到完。这里介绍一下php内部对于连接处理的三种状态。

0 - NORMAL(正常)

1 - ABORTED(异常退出)

2 - TIMEOUT(超时)

当 PHP 脚本正常地运行 NORMAL 状态时,连接为有效。当远程客户端中断连接时,ABORTED 状态的标记将会被打开。远程客户端连接的中断通常是由用户点击 STOP 按钮导致的。当连接时间超过 PHP 的时限(请参阅set_time_limit() 函数)时,TIMEOUT 状态的标记将被打开。

脚本中,这三种状态值可以通过connection_status()函数来获取,而注意了,其实php中并不是每次的输出都会自动去检测这个值,而是只有当输出缓冲池满了后才会去触发(同理,浏览器收到请求时也不会立刻输出在页面上,而是缓冲池满了才会输出,这种措施有利于提高系统效率)。这里插个外话,我们可以为程序注册一个关闭函数,register_shutdown_function(),通过这个注册函数,当php异常退出,或者超时时都会触发关闭函数,这样我们可以执行一些任务来追踪http状态码是499或502,或者执行一些任务来处理这些异常请求。

关于连接处理的详细可以看这里:http://php.net/manual/zh/features.connection-handling.php

下面回到正文,既然知道了如果保持会话连接了,那如何主动断开http请求?答案很简单,利用header()函数既可以了。

header(“Content-Length:XXX”):Content-Length的作用:浏览器接收到指定Content-Length大小的消息实体后,则会断开与服务器的连接。

header(“Connection: Close”):Connection的作用:浏览器接收到Connection的Close或Keep-Alive后,决定是关闭连接还是继续使用当前的连接进下一次请求。

有关Content-Length,这里又得偏离话题介绍一个知识点,关于ob。

 

这是一个程序例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$a = '';
$size = 0;
set_time_limit(0);
ob_implicit_flush(true);
ignore_user_abort (true);
 
$json = "{'t':'xxx','dd':'xxxx'}";
echo $json;
$size=ob_get_length();
header("Content-Length: $size"); 
header("Connection: close");
header("HTTP/1.1 200 OK");
ob_flush();
 
sleep(5);
file_put_contents('.\client_test.txt', $json);

这个例子里面有几个注意的点:

1、执行任务时记得带上set_time_limit(0),否则后端可能会执行不完。

2、header()函数执行,输出http表头前,脚本不可以有任何输出,否者会有报错,因此这里要利用ob来做缓冲。

 

 

 

 

下篇文章分析客户端主动断开后服务端是否还会继续运行任务。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>