使用fastcgi_finish_request 处理耗时的任务

本文介绍如何使用fastcgi_finish_request()函数解决耗时任务导致的浏览器超时问题,通过将耗时任务如生成大文件、发送邮件等转为后台执行,实现快速响应,改善用户体验。

我们业务中经常遇到这样的场景:比如生成文件较大的excel ,非常耗时,有可能需要5到30妙的时间,甚至更长导致浏览器连接超时。
另外一个就是体验问题,用户需要长时间的等待响应的完毕,体验较差。
类似的场景还有
1:需要处理大的文件
2:发送邮件或短信,尤其是需要循环发送邮件通知等
3:调用远程耗时的api 等

遇到这种情况,如果您的服务器使用的也是nginx ,那么可以考虑使用下面的函数

fastcgi_finish_request();

该函数的作用:
理解发送响应给浏览器,这样用户的等待时间很短,但是php进程其实还在服务器中运行。
这样就达到了两个目录目的,有点类似于异步任务

  1. 响应快:比如发送邮件需要3秒时间,但用户无感知,1妙之内就告诉用户发送邮件完毕
  2. 耗时任务后台执行:浏览器响应结束了,用户可以做其他的事情。后台进程默默的执行发送邮件等任务

举例效果图:
1:该程序模拟一个耗时的任务,需要5妙才能执行完毕
在这里插入图片描述
经过上面的演示,我们达到了目的
1:很快的响应,1毫米之内,浏览器响应结束
2:后台任务,注意右侧上方的日志,每秒输出一个时间戳

全部测试代码如下

 <?php
/**
 * 设置超时时间,变成不限制
 *
 */
set_time_limit(0);

/**
 * 本函数模拟非常耗时的任务,执行完毕需要5秒的时间
 */
 function writeFile()
 {
     $path = '/home/ndw/test/1.txt';
     file_put_contents($path,'程序运行开始' . PHP_EOL,FILE_APPEND);
     for($i =0;$i < 5;$i++) {
         file_put_contents($path,time() . PHP_EOL,FILE_APPEND);
         sleep(1);
     }

     file_put_contents($path,'程序运行结束' . PHP_EOL,FILE_APPEND);

 }

/**
 * 输出文字标记,任务开始
 */
echo('任务开始');

/**
 *  后台执行非常耗时的任务
 */
register_shutdown_function(writeFile);

/**
 * 立即发送请求
 */
fastcgi_finish_request();


备注:

  • 主角是fastcgi_finish_request,其实把要执行的代码放到该函数的后面,就可以了。
  • register_shutdown_function函数,具体百度,这个函数主要是为了考虑修改成本,有的程序已经成型,不方便作大的调整,可以把函数提前注册,这样他是不会立即执行的。页面响应完毕后,再调用本函数
  • 建议不要滥用,适合一些耗时但流程简单的任务(比如发送邮件)。因为是后台执行,如果程序出错,前台是看不到的,需要有日志记录和重试机制。
<think>我们正在分析Nginx配置中与FastCGI相关的两个关键指令:`fastcgi_param`和`include`,特别是针对以下配置行: fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; 根据引用内容,我们逐步解释: 1. **`include fastcgi_params;` 的作用**: - 引用[2]指出:`fastcgi_params` 是一个文件,其中包含了Nginx预定义的一组FastCGI参数(常量)。这些参数是Nginx与FastCGI进程(如PHP-FPM)通信时所必需传递的。 - 默认情况下,这个文件位于Nginx配置目录(例如:`/etc/nginx/`)中,其内容定义了多个`fastcgi_param`参数,例如: ```nginx fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; ...(其他参数) ``` 注意:在默认的`fastcgi_params`文件中,`SCRIPT_FILENAME`参数可能被设置为`$fastcgi_script_name`(即只有脚本文件名,没有完整路径)[^2]。 2. **`fastcgi_param SCRIPT_FILENAME ...` 的作用**: - 引用[1]详细解释了这一行: - `fastcgi_param` 是Nginx指令,用于设置传递给FastCGI进程的参数。 - `SCRIPT_FILENAME` 是FastCGI协议中的一个特殊参数,它告诉PHP-FPM要执行哪个脚本文件。 - `$document_root` 是Nginx内置变量,表示当前请求的根目录(通常由`root`指令设置)。 - `$fastcgi_script_name` 是Nginx内置变量,表示请求的脚本文件名(例如:`/index.php`)。 - 因此,`$document_root$fastcgi_script_name` 拼接后得到脚本的完整文件系统路径(例如:`/usr/share/nginx/html/index.php`)[^1]。 3. **为什么需要单独设置 `SCRIPT_FILENAME`?** - 引用[2]和引用[3]提到:默认的`fastcgi_params`文件可能没有正确设置`SCRIPT_FILENAME`(仅设置为`$fastcgi_script_name`),这会导致PHP-FPM找不到脚本文件,从而出现空白页或“File not found”错误。 - 因此,在配置中显式设置 `SCRIPT_FILENAME` 为 `$document_root$fastcgi_script_name` 是为了覆盖默认值,确保传递正确的脚本路径[^1][^2][^3]。 4. **配置顺序的重要性**: - 由于Nginx配置中相同参数后出现的指令会覆盖前面的值,因此我们通常在`include fastcgi_params;`之后(或之前)单独设置`SCRIPT_FILENAME`。但更常见的做法是先包含通用参数,再覆盖特定参数: ```nginx include fastcgi_params; # 包含默认参数(其中SCRIPT_FILENAME可能不正确) fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; # 覆盖为正确值 ``` **总结**: - `include fastcgi_params;` 引入一组通用的FastCGI参数。 - `fastcgi_param SCRIPT_FILENAME ...` 专门设置脚本的完整路径,确保PHP-FPM能定位到待执行的PHP文件。 **完整配置示例**: ```nginx location ~ \.php$ { root /usr/share/nginx/html; fastcgi_pass 127.0.0.1:9000; include fastcgi_params; # 包含基础参数 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; # 覆盖关键参数 } ``` **验证方法**: 1. 检查Nginx错误日志(`/var/log/nginx/error.log`)是否有“Primary script unknown”错误(表明路径错误)。 2. 在PHP脚本中输出`$_SERVER['SCRIPT_FILENAME']`,确认路径与实际一致。 §§相关问题§§ 1. Nginx 内置变量 `$document_root` 和 `$fastcgi_script_name` 分别代表什么? 2. 为什么默认的 `fastcgi_params` 文件可能导致 PHP 脚本无法执行? 3. 如何自定义 FastCGI 参数传递到 PHP-FPM? 4. 除了 `SCRIPT_FILENAME`,还有哪些 FastCGI 参数对 PHP 执行至关重要?</think>### Nginx FastCGI 配置详解 #### 1. `fastcgi_param` 指令解析 ```nginx fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; ``` - **作用**:向 PHP-FPM 传递关键执行参数 - **组成要素**: - `SCRIPT_FILENAME`:PHP-FPM 用于定位脚本的核心参数[^1] - `$document_root`:Nginx 变量,表示当前站点的根目录路径(由 `root` 指令定义) - `$fastcgi_script_name`:Nginx 变量,包含请求的脚本路径(如 `/index.php`) - **实际效果**:拼接出 PHP 文件的完整物理路径 示例:若请求 `/index.php`,则拼接为 `/usr/share/nginx/html/index.php` #### 2. `include` 指令解析 ```nginx include fastcgi_params; ``` - **作用**:加载预定义的 FastCGI 参数集合 - **文件位置**:通常位于 `/etc/nginx/fastcgi_params` - **包含内容**: ```nginx # 基础通信参数 fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; # 服务器环境参数 fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param SERVER_PROTOCOL $server_protocol; # 客户端信息 fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; ``` #### 3. 组合工作流程 ```mermaid graph LR A[客户端请求 index.php] --> B[Nginx接收请求] B --> C[include fastcgi_params 加载基础参数] C --> D[fastcgi_param SCRIPT_FILENAME 设置脚本路径] D --> E[将完整参数集传递给PHP-FPM] E --> F[PHP-FPM执行 /usr/share/nginx/html/index.php] ``` #### 4. 关键注意事项 1. **覆盖关系**: - `include fastcgi_params` 默认设置 `SCRIPT_FILENAME = $fastcgi_script_name`(仅文件名)[^2] - 后续的 `fastcgi_param` 会覆盖同名参数,因此必须显式设置完整路径 2. **常见错误**: - 空白页:通常因 `SCRIPT_FILENAME` 路径错误导致 PHP-FPM 找不到文件[^3] - 502错误:`fastcgi_pass` 地址与 PHP-FPM 监听地址不匹配 3. **最佳实践**: ```nginx location ~ \.php$ { # 先包含基础参数 include fastcgi_params; # 再覆盖关键路径参数 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; # 添加安全限制 try_files $uri =404; } ``` #### 5. 参数传递原理 当 Nginx 处理 PHP 请求时: 1. 通过 `include fastcgi_params` 加载基础环境变量 2. 使用 `fastcgi_param` 添加/修改特定参数 3. 所有参数以键值对形式发送给 PHP-FPM 4. PHP-FPM 将这些参数转换为 `$_SERVER` 超全局变量 > 示例:`fastcgi_param TEST "value"` 在 PHP 中可通过 `$_SERVER['TEST']` 访问
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值