Heroku部署后Public目录下PHP文件出现404错误且Ajax调用失败的排查求助
问题根源
首先要明确:你当前用的是Heroku的Node.js环境(buildpack),这个环境默认只运行Node.js/Express应用,没有安装PHP运行时,所以你的PHP文件只会被当作普通静态文件处理——这就是为什么直接访问会触发下载(浏览器识别不出它是可执行的服务器端脚本),而AJAX请求时虽然文件存在,但根本没有被解析执行,相当于你请求的只是一个文本文件,而非预期的接口响应。
推荐解决方案:将PHP逻辑迁移到Node.js
既然你已经在使用Express,最简洁且易维护的方式是把PHP里的数据库操作逻辑迁移到Node.js中,完全去掉PHP依赖:
替换数据库连接逻辑:
比如原来的db_connect.php,可以用Node.js的数据库库替代(比如MySQL用mysql2,PostgreSQL用pg)。安装依赖:npm install mysql2然后在Express里创建数据库连接模块,比如
db.js:const mysql = require('mysql2/promise'); const pool = mysql.createPool({ host: process.env.DB_HOST, user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_NAME, waitForConnections: true, connectionLimit: 10, queueLimit: 0 }); module.exports = pool;创建替代PHP接口的Express路由:
把load_posts.php的逻辑改成Express的API路由,比如在app.js里添加:const pool = require('./db'); app.get('/api/load-posts', async (req, res) => { try { const [rows] = await pool.query('SELECT * FROM posts'); // 替换成你的查询语句 res.json(rows); } catch (err) { console.error(err); res.status(500).json({ error: 'Failed to load posts' }); } });修改前端AJAX请求地址:
在custom.js里把请求地址从/php/load_posts.php改成/api/load-posts即可。
备选方案:在Heroku上同时运行Node.js和PHP(不推荐)
如果你一定要保留PHP代码,需要配置Heroku使用多buildpack,同时运行Node.js和PHP服务,步骤如下(复杂度较高,维护成本高):
添加多buildpack:
在终端执行:heroku buildpacks:add heroku/nodejs heroku buildpacks:add heroku/php确保Node.js buildpack排在前面。
配置Procfile和代理:
需要创建Procfile来启动Node.js服务器和PHP-FPM,同时用Nginx反向代理区分静态资源、Node.js路由和PHP请求。这部分配置比较繁琐,需要编写Nginx配置文件,并且处理端口转发问题,适合有一定运维经验的开发者。
额外说明
你之前遇到的“直接访问PHP文件会下载”是因为Express默认给.php文件设置的MIME类型不对,即使你手动设置MIME类型(比如application/x-httpd-php),也只是让浏览器尝试解析,但Heroku环境没有PHP解释器,依然无法执行脚本,所以这不是根本解决方案。
内容的提问来源于stack exchange,提问作者Eric.18

