# 11.10 故障排查手册 :::tip 排查思路 遇到问题时,按以下顺序排查: 1. 查看 PHP 错误日志(`/var/log/php_errors.log`) 2. 查看 Nginx 错误日志(`/var/log/nginx/error.log`) 3. 查看浏览器控制台(F12) 4. 检查 `.env` 配置是否正确 ::: ## 服务器问题 ### 502 Bad Gateway PHP-FPM 未启动或配置错误: ```bash # ----------------------------------------------------------------------------- # 检查 PHP-FPM 服务状态 # ----------------------------------------------------------------------------- # status → 显示服务是否正在运行、主进程 PID、内存占用等 sudo systemctl status php8.2-fpm # ----------------------------------------------------------------------------- # 重启 PHP-FPM(最常见的修复方式) # ----------------------------------------------------------------------------- # restart → 停止后重新启动,所有正在处理的请求会被中断 sudo systemctl restart php8.2-fpm # ----------------------------------------------------------------------------- # 实时查看 PHP-FPM 错误日志(Ctrl+C 退出) # ----------------------------------------------------------------------------- # -f → follow 模式,持续输出新增日志 sudo tail -f /var/log/php8.2-fpm.log ``` ### 500 Internal Server Error ```bash # ----------------------------------------------------------------------------- # 查看 PHP 错误日志(定位 PHP 脚本执行错误) # ----------------------------------------------------------------------------- # tail -f → 实时输出新增日志行 sudo tail -f /var/log/php_errors.log # ----------------------------------------------------------------------------- # 查看 Nginx 错误日志(定位 Nginx 层错误) # ----------------------------------------------------------------------------- sudo tail -f /var/log/nginx/error.log # ----------------------------------------------------------------------------- # 检查运行时目录权限(500 错误常见原因) # ----------------------------------------------------------------------------- # -la → 显示详细信息(包括隐藏文件) ls -la /www/api/runtime/ ``` ### 404 Not Found Nginx URL 重写配置错误: ```nginx # 检查 try_files 或 rewrite 规则 # $uri → 当前请求的文件路径 # $uri/ → 当前请求的目录路径 # /index.php?s=$uri&$args → 回退到 ThinkPHP 入口,传递原始路径和参数 location / { try_files $uri $uri/ /index.php?s=$uri&$args; } ``` ## 数据库问题 ### MySQL 连接失败 ```bash # ----------------------------------------------------------------------------- # 检查 MySQL 服务状态 # ----------------------------------------------------------------------------- sudo systemctl status mysql # ----------------------------------------------------------------------------- # 测试数据库连接(SELECT 1 是最简单的查询,验证连接是否正常) # ----------------------------------------------------------------------------- mysql -u root -p -e "SELECT 1" # ----------------------------------------------------------------------------- # 检查用户权限(查看所有用户及其允许的连接来源) # ----------------------------------------------------------------------------- # user → 用户名,host → 允许连接的主机(% 表示任意) mysql -u root -p -e "SELECT user, host FROM mysql.user;" # ----------------------------------------------------------------------------- # 允许远程连接(生产环境慎用,建议通过 SSH 隧道连接) # ----------------------------------------------------------------------------- # GRANT ALL → 授权所有权限 # ON `数据库`.* → 指定数据库的所有表 # TO 'root'@'%' → 允许从任意主机连接的 root 用户 # IDENTIFIED BY → 设置密码 mysql -u root -proot -e "GRANT ALL ON \`rxthinkcmf.thinkphp8.elevue\`.* TO 'root'@'%' IDENTIFIED BY 'root';" mysql -u root -p -e "FLUSH PRIVILEGES;" # 刷新权限使配置生效 ``` ### PostgreSQL 连接失败 ```bash # ----------------------------------------------------------------------------- # 检查 PostgreSQL 服务状态 # ----------------------------------------------------------------------------- sudo systemctl status postgresql # ----------------------------------------------------------------------------- # 测试连接(-U 指定用户,-d 指定数据库,-c 执行 SQL) # ----------------------------------------------------------------------------- psql -U postgres -d rxthinkcmf.thinkphp8.elevue -c "SELECT 1;" # ----------------------------------------------------------------------------- # 检查客户端认证配置(pg_hba.conf 控制哪些 IP 可以连接) # ----------------------------------------------------------------------------- sudo nano /etc/postgresql/*/main/pg_hba.conf # 添加以下行允许所有 IP 通过密码连接: # host all all 0.0.0.0/0 md5 # 重启使配置生效 sudo systemctl restart postgresql ``` ### SQLite 连接失败 ```bash # ----------------------------------------------------------------------------- # 检查 SQLite 数据库文件是否存在 # ----------------------------------------------------------------------------- # -la → 显示文件大小、权限、修改时间 ls -la /www/api/runtime/database.sqlite # ----------------------------------------------------------------------------- # 修复文件权限(确保 Web 服务器用户可读写) # ----------------------------------------------------------------------------- # 664 → owner/group 可读写,others 只读 chmod 664 /www/api/runtime/database.sqlite chown www-data:www-data /www/api/runtime/database.sqlite ``` ### SQL Server 连接失败 ```bash # ----------------------------------------------------------------------------- # 检查 SQL Server 服务状态 # ----------------------------------------------------------------------------- sudo systemctl status mssql-server # ----------------------------------------------------------------------------- # 测试连接(-S 服务器,-U 用户,-P 密码,-Q 执行查询) # ----------------------------------------------------------------------------- sqlcmd -S localhost -U sa -P root -Q "SELECT 1" # ----------------------------------------------------------------------------- # 检查 PHP 的 SQL Server 扩展是否安装 # ----------------------------------------------------------------------------- php -m | grep pdo_sqlsrv # 查找 pdo_sqlsrv 扩展 ``` ### 数据库表不存在 ```bash # ----------------------------------------------------------------------------- # 重新导入初始化 SQL(按数据库类型选择对应命令) # ----------------------------------------------------------------------------- # MySQL:通过 mysql 命令导入 SQL 文件 mysql -u root -proot rxthinkcmf.thinkphp8.elevue < document/mysql/rxthinkcmf.thinkphp8.elevue.sql # PostgreSQL:通过 psql 命令导入 SQL 文件 # -U 指定用户,-d 指定数据库,-f 指定 SQL 文件 psql -U postgres -d rxthinkcmf.thinkphp8.elevue -f document/postgresql/rxthinkcmf.thinkphp8.elevue.sql # SQLite:通过 sqlite3 命令导入 SQL 文件 sqlite3 /www/api/runtime/database.sqlite < document/sqlite/rxthinkcmf.thinkphp8.elevue.sql ``` ## PHP 问题 ### 缺少扩展 ```bash # ----------------------------------------------------------------------------- # 查看已安装的 PHP 扩展列表 # ----------------------------------------------------------------------------- php -m # 列出所有已加载的扩展 # ----------------------------------------------------------------------------- # 安装缺失的扩展(按数据库类型选择) # ----------------------------------------------------------------------------- sudo apt install php8.2-mysql # MySQL 驱动(pdo_mysql) # sudo apt install php8.2-pgsql # PostgreSQL 驱动(取消注释以安装) # sudo apt install php8.2-sqlite3 # SQLite 驱动(取消注释以安装) # ----------------------------------------------------------------------------- # 重启 PHP-FPM 使新扩展生效 # ----------------------------------------------------------------------------- sudo systemctl restart php8.2-fpm ``` ### 内存不足 ```ini ; php.ini — 增加单脚本最大内存限制 ; 默认 128M,Excel 导出等大内存操作建议设为 256M 或更高 memory_limit = 256M ``` ### 执行超时 ```ini ; php.ini — 增加单脚本最大执行时间 ; 默认 30 秒,长时间操作(如数据迁移)建议设为 300 秒 max_execution_time = 300 ``` ## 权限问题 ```bash # ----------------------------------------------------------------------------- # 修复项目目录权限(owner 为 Web 服务器用户) # ----------------------------------------------------------------------------- # chown → 修改文件所有者(-R 递归) # chmod → 修改文件权限(755 = owner 全权限,group/others 可读可执行) sudo chown -R www-data:www-data /www/api/ sudo chmod -R 755 /www/api/ # ----------------------------------------------------------------------------- # 修复运行时目录(必须可写 — ThinkPHP 缓存、日志、编译模板) # ----------------------------------------------------------------------------- # 777 = 所有人可读写执行(仅限运行时目录,不要用于项目根目录) sudo chmod -R 777 /www/api/runtime/ # ----------------------------------------------------------------------------- # 修复上传目录(必须可写 — 用户上传文件存储位置) # ----------------------------------------------------------------------------- sudo chmod -R 755 /opt/data/uploads/ sudo chown -R www-data:www-data /opt/data/uploads/ ``` ## 业务问题 ### 401 未授权 ```bash # ----------------------------------------------------------------------------- # 检查 Token 是否正确携带 # ----------------------------------------------------------------------------- # -H "Authorization: Bearer " → 在请求头中携带 JWT Token # 替换为实际的 access_token 值 curl -H "Authorization: Bearer " http://localhost:8000/api/index/getUser # ----------------------------------------------------------------------------- # 检查 JWT 密钥配置 # ----------------------------------------------------------------------------- # 确认 .env 中的 JWT.SECRET 与后端代码一致 grep JWT.SECRET .env ``` ### 403 禁止访问 ```bash # ----------------------------------------------------------------------------- # 检查用户角色分配(用户是否分配了角色) # ----------------------------------------------------------------------------- # think_user_role 表存储用户与角色的关联关系 mysql -u root -proot rxthinkcmf.thinkphp8.elevue -e "SELECT * FROM think_user_role WHERE user_id=1;" # ----------------------------------------------------------------------------- # 检查角色权限(角色是否分配了菜单权限) # ----------------------------------------------------------------------------- # think_role_menu 表存储角色与菜单的关联关系 mysql -u root -proot rxthinkcmf.thinkphp8.elevue -e "SELECT * FROM think_role_menu WHERE role_id=1;" ``` ### 文件上传失败 ```bash # ----------------------------------------------------------------------------- # 检查上传目录权限和空间 # ----------------------------------------------------------------------------- # -la → 显示详细信息(权限、大小、修改时间) ls -la /opt/data/uploads/ # ----------------------------------------------------------------------------- # 检查 PHP 上传限制配置 # ----------------------------------------------------------------------------- # php -i → 输出 PHP 配置信息 # grep → 过滤出上传相关的配置项 php -i | grep upload_max_filesize # 单文件最大上传大小 php -i | grep post_max_size # POST 请求最大大小 ``` ### Token 频繁过期 ```bash # ----------------------------------------------------------------------------- # 检查 JWT Token 过期时间配置 # ----------------------------------------------------------------------------- # grep → 从 .env 文件中提取 ACCESS_TTL 配置值 grep JWT.ACCESS_TTL .env # 默认 7200 秒(2 小时),可在 .env 中调整 # 如果需要更长的登录状态,增大此值或使用 refresh_token 机制 ``` ### 日志中 IP 显示 127.0.0.1 部署在 CDN / 负载均衡 / Nginx 反向代理后面时,日志中的 IP 可能显示为 `127.0.0.1`。 ```bash # ----------------------------------------------------------------------------- # 第 1 步:检查 .env 中是否配置了 PROXY_IPS # ----------------------------------------------------------------------------- grep PROXY_IPS .env # 如果为空或未配置,添加受信代理 IP(以腾讯云 CDN 为例): # PROXY_IPS = 127.0.0.1,::1,101.226.0.0/15,180.101.0.0/16,182.254.0.0/16 # ----------------------------------------------------------------------------- # 第 2 步:检查 Nginx 是否错误覆盖了代理头 # ----------------------------------------------------------------------------- # 如果 Nginx 配置中有以下行,需要删除: # fastcgi_param REMOTE_ADDR $remote_addr; # fastcgi_param HTTP_X_REAL_IP $remote_addr; # fastcgi_param HTTP_X_FORWARDED_FOR $remote_addr; # 这些会覆盖 CDN 传递的真实 IP 头 grep -r "fastcgi_param.*REMOTE_ADDR\|fastcgi_param.*X_REAL_IP\|fastcgi_param.*X_FORWARDED" /etc/nginx/ # ----------------------------------------------------------------------------- # 第 3 步:清除缓存并重载 # ----------------------------------------------------------------------------- rm -rf runtime/* nginx -s reload ``` ## 定时任务问题 ### 任务不执行 ```bash # ----------------------------------------------------------------------------- # 查看当前用户的 crontab 配置(确认任务是否已添加) # ----------------------------------------------------------------------------- # -l → 列出当前 crontab 中的所有任务 crontab -l # ----------------------------------------------------------------------------- # 检查 cron 服务是否运行 # ----------------------------------------------------------------------------- sudo systemctl status cron # ----------------------------------------------------------------------------- # 手动执行任务(验证命令是否能正常运行) # ----------------------------------------------------------------------------- # cd /www/api → 切换到项目目录(crontab 环境变量不完整,需手动 cd) cd /www/api && php think job:run # ----------------------------------------------------------------------------- # 查看 cron 执行日志(排查任务是否被触发) # ----------------------------------------------------------------------------- # grep CRON → 过滤包含 CRON 的日志行 sudo tail -f /var/log/syslog | grep CRON ``` ### 任务重复执行 ```bash # ----------------------------------------------------------------------------- # 检查是否有多个 job:run 进程同时运行 # ----------------------------------------------------------------------------- # ps aux → 列出所有进程 # grep job:run → 过滤出 job:run 相关进程 ps aux | grep job:run # ----------------------------------------------------------------------------- # 检查 Daemon 守护进程 # ----------------------------------------------------------------------------- ps aux | grep job:daemon ``` ## 前端问题 ### API 请求 404 ```bash # ----------------------------------------------------------------------------- # 测试后端路由是否正常(绕过前端,直接请求 API) # ----------------------------------------------------------------------------- # -H → 设置请求头(携带 JWT Token) curl http://localhost:8000/api/example/page -H "Authorization: Bearer " # ----------------------------------------------------------------------------- # 检查 Nginx 配置语法是否正确 # ----------------------------------------------------------------------------- # -t → test 模式,检查配置文件语法(不实际重载) sudo nginx -t ``` ### 白屏 打开浏览器 F12 控制台查看错误,常见原因: 1. JS 加载失败 2. 路由配置错误 3. Token 过期 ### 构建失败 ```bash # ----------------------------------------------------------------------------- # 清理并重新安装依赖(修复依赖冲突或缓存损坏) # ----------------------------------------------------------------------------- cd ui rm -rf node_modules pnpm-lock.yaml # 删除依赖目录和锁文件 pnpm install # 重新安装所有依赖 pnpm build # 重新构建 ```