Azure定时触发函数调用App Service接口未生成备份文件问题
我有一个基于定时器触发的Azure Node.js Function,代码如下:
const { app } = require('@azure/functions'); app.timer('Cron', { schedule: '0 0 */1 * * *', handler: async (timer, context) => { const url = 'https://xxx/backup/index.php'; const headers = { 'key': 'key' }; await fetch(url, { headers }) .then(resp => resp.text()) .then(data => { context.log(data); }) .catch(err => { context.log(err); }); } });
该函数会向部署在Azure App Service上的PHP备份脚本发起GET请求。当我通过浏览器手动访问该脚本URL(https://xxx/backup/index.php)时,能正常生成备份文件;但当Azure函数运行时,虽然Nginx访问日志显示请求来自Azure函数且返回HTTP 200状态码,却未生成备份文件。即使在Azure门户的函数代码测试编辑器中手动运行函数,结果依然如此。
手动访问时的Nginx日志:
xxx.xxx.xxx.xxx - - [03/Dec/2023:09:12:41 +0000] "GET /backup/ HTTP/1.1" 200 100 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"
Azure函数调用时的Nginx日志:
xxx.xxx.xxx.xxx - - [03/Dec/2023:07:17:00 +0000] "GET /backup/index.php HTTP/1.1" 200 31 "-" "undici"
App Service上的PHP备份脚本代码如下:
<?php require 'vendor/autoload.php'; $dotenv = Dotenv\Dotenv::createImmutable(__DIR__, '../../.env'); $dotenv->load(); $host = $_ENV['DB_HOST']; $username = $_ENV['DB_USERNAME']; $password = $_ENV['DB_PASSWORD']; $database = $_ENV['DB_DATABASE']; $encryption_key = $_ENV['ENCRYPTION_KEY']; $ssl_cert = $_ENV['MYSQL_ATTR_SSL_CA']; $encFile = './backup-'.date('d-m-Y') .'.sql.gz.enc'; // MySQL dump command, gzip, and encrypt in a single pipeline $command = sprintf( 'mysqldump --no-tablespaces --ssl=1 --ssl-ca=%s -h %s -u %s -p%s %s | gzip -9 | openssl enc -aes-256-cbc -salt -k %s > %s', $ssl_cert, $host, $username, $password, $database, $encryption_key, $encFile ); // Execute the pipeline exec($command, $output, $exitCode); if ($exitCode !== 0) die("Backup failed with exit code $exitCode\n"); echo "Backup completed successfully. Filename: $encFile\n"; ?>
目前脚本尚未添加认证机制(可忽略Node.js代码中的自定义请求头),请问我遗漏了什么配置或步骤?
排查与解决方案
1. 工作目录与路径问题
脚本中使用相对路径./backup-xxx指定备份文件位置,Azure App Service中PHP进程的当前工作目录可能与手动访问时不同(比如手动访问时工作目录是/backup/,而函数触发请求时可能是网站根目录),导致文件写入到了预期外的路径,或者因权限不足无法写入。
解决方法:
- 使用绝对路径指定备份文件:将
$encFile改为$encFile = __DIR__ . '/backup-'.date('d-m-Y') .'.sql.gz.enc';,__DIR__表示当前PHP脚本所在的/backup/目录,确保文件写入到预期位置。 - 检查目录权限:确认App Service中运行PHP的进程(通常为
www-data)对/backup/目录有写入权限,可通过App Service门户的“高级工具”->“Kudu”进入文件管理器查看权限。
2. exec命令执行环境差异
手动访问与Azure函数触发请求时,PHP进程的环境变量可能存在差异,导致mysqldump、gzip、openssl等工具无法被找到,或者.env文件加载失败。
解决方法:
- 使用工具的绝对路径:修改exec命令中的工具路径为绝对路径,比如
/usr/bin/mysqldump、/usr/bin/gzip、/usr/bin/openssl,避免PATH环境变量不一致的问题。 - 捕获exec执行的详细错误:修改exec命令,将错误输出重定向到标准输出,方便排查问题:
exec($command . ' 2>&1', $output, $exitCode); // 输出所有执行信息,Azure函数调用时可通过context.log查看 print_r($output); - 验证.env文件加载:确认
../../.env的路径是否正确,可改为绝对路径加载,比如$dotenv = Dotenv\Dotenv::createImmutable('/home/site/wwwroot');(假设网站根目录为/home/site/wwwroot)。
3. App Service PHP配置限制
Azure App Service可能在PHP配置中禁用了exec函数,或者限制了系统命令的执行权限。
解决方法:
- 检查PHP禁用函数:进入App Service门户的“配置”->“常规设置”,查看对应PHP版本的
disable_functions配置,确保exec未被列入其中;也可通过在PHP脚本中执行phpinfo();查看配置详情。 - 若需要启用exec,可通过添加
.user.ini文件到网站根目录,修改配置:disable_functions = ""(清空禁用列表,需根据实际需求调整)。
4. 请求路径细微差异
手动访问的是/backup/(可能通过目录索引触发index.php),而Azure函数调用的是/backup/index.php,虽然返回200,但可能存在URL重写或目录权限的细微差异。
解决方法:
修改Node.js函数中的请求URL为https://xxx/backup/,测试是否能正常生成备份文件。
内容的提问来源于stack exchange,提问作者Chen Luu

