使用FETCH请求时出现FastCGI PHP文件找不到问题排查
问题描述
我正在做一个学习Docker的项目,采用NextJS+PHP后端+Nginx架构。目前项目已能正常运行:通过浏览器地址栏访问API时,会返回预期的错误页面,Nginx无报错。但使用FETCH请求API时,PHP-FPM容器返回“file not found”,Nginx则报错“FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream”。
站点Nginx配置如下:
upstream next_app { # NextJS running app port server nextapp:3000; } upstream php_fpm { # PHP FPM server URI and port server phpapp:9000; } server { listen 80 default_server; server_name _; server_tokens off; error_log /var/log/nginx/error.log; access_log /var/log/nginx/access.log; location ~ ^/api { root /var/www; try_files /www/index.php =404; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_pass php_fpm; } # proxy pass for NodeJS app proxy_http_version 1.1; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; location / { proxy_pass http://next_app; } }
设计思路是让所有以/api开头的请求都走PHP接口,怀疑是NextJS的Fetch机制导致问题,但未找到解决办法,请问该如何修复?
问题根源
浏览器地址栏访问和Fetch请求的差异在于请求路径的处理:直接在浏览器访问/api/xxx时,Nginx匹配location ~ ^/api后,try_files直接指定了/www/index.php,刚好命中文件;但Fetch请求时,NextJS的路径处理可能导致$fastcgi_script_name变成/api/xxx,结合root /var/www,SCRIPT_FILENAME就变成了/var/www/api/xxx,而这个文件在PHP容器中不存在,因此触发"Primary script unknown"错误。
另外原有try_files写法存在问题:/www/index.php是绝对路径,结合root /var/www,实际会查找/var/www/www/index.php,这大概率不是PHP文件的实际位置。
修复步骤
1. 修正Nginx的API location配置
假设PHP入口文件index.php在PHP容器的/var/www目录下(所有/api请求通过该入口做路由),调整location ~ ^/api块:
location ~ ^/api { root /var/www; # 所有/api请求转发到index.php,保留查询参数用于路由解析 try_files $uri $uri/ /index.php?$query_string; include fastcgi_params; # 指定正确的PHP入口文件路径 fastcgi_param SCRIPT_FILENAME $document_root/index.php; # 传递原始请求路径给PHP,用于路由处理 fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info; fastcgi_pass php_fpm; }
如果需要每个/api子路径对应单独的PHP文件,需确保$document_root$fastcgi_script_name指向PHP容器中实际存在的文件,同时匹配Nginx的root配置。
2. 验证PHP容器的文件路径
进入PHP-FPM容器,确认PHP文件的实际位置:
docker exec -it phpapp bash ls -l /var/www
确保index.php(或对应API文件)存在于/var/www目录,否则调整Nginx的root参数指向PHP文件的实际根目录。
3. 检查NextJS的Fetch请求路径
确保NextJS中Fetch请求使用绝对路径(如/api/xxx),避免相对路径或带域名的路径,确保Nginx能匹配到location ~ ^/api规则。
关键说明
try_files按顺序检查文件/目录,不存在则转发到指定入口,确保所有/api请求都由PHP入口处理路由。SCRIPT_FILENAME必须精确指向PHP容器中存在的文件,否则PHP-FPM会返回"file not found"。- 开发环境下需注意NextJS开发服务器的代理配置,确保代理指向Nginx的API路径,而非直接请求PHP容器。
内容的提问来源于stack exchange,提问作者sjiamnocna

