Heroku是否允许应用访问80默认端口外的其他端口?5000端口无响应
核心规则
Heroku不支持对外暴露80(HTTP)、443(HTTPS)以外的自定义端口,所有打到其他外部端口的请求会被平台路由层直接拦截丢弃,根本不会到达你的应用进程,这就是你访问:5000/graphql无响应的直接原因。
补充说明:Heroku的dyno内部进程之间可以任意使用本地端口通信,没有限制,只有对外提供服务的入口必须绑定平台动态分配的端口(通过环境变量PORT注入,每次启动可能变化,不是固定值),平台会自动把公网80/443端口的请求转发到这个绑定了PORT的进程上。
问题根因
你现在的部署里,负责渲染网页的Node服务已经正确绑定了PORT环境变量对应的端口,所以根路径网页可以正常访问;但postgraphile单独绑定了固定的5000端口,既没有和主服务统一入口,也没有绑定平台要求的PORT值,平台路由不会把/graphql路径的请求转发到5000端口上,自然没有响应。
可行修复方案
方案1:将postgraphile作为中间件挂载到现有Node服务(最推荐)
不要让postgraphile作为独立进程监听单独端口,直接把它集成到你已经正常运行的Node Web服务中,统一监听PORT环境变量指定的端口,之后直接访问https://appname.herokuapp.com/graphql即可,不需要带任何端口号。
如果你用Express作为Web框架,参考代码:
const express = require('express'); const { postgraphile } = require('postgraphile'); const app = express(); // 保留你原有的网页路由逻辑 app.get('/', (req, res) => res.send('你的网页内容')); // 挂载postgraphile中间件,连接串直接用Heroku配置的环境变量即可 app.use( postgraphile(process.env.DATABASE_URL, 'public', { graphiql: process.env.NODE_ENV === 'development', // 生产环境按需关闭图形化调试页 }) ); // 严格绑定平台分配的端口,禁止写死固定值 const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`服务已启动,监听端口${PORT}`); });
方案2:单独部署postgraphile时正确配置端口
如果你的应用不需要跑其他Web服务,只需要提供postgraphile接口,直接修改postgraphile的启动命令,不要写死5000端口,强制绑定平台分配的PORT即可:
postgraphile --connection $DATABASE_URL --port $PORT --schema public
部署完成后同样直接访问不带端口的/graphql路径即可。
方案3:本地反向代理转发(适合不想改动postgraphile启动逻辑的场景)
如果你需要保留postgraphile作为独立进程跑在5000端口,可以在现有Node Web服务中增加反向代理规则,把公网/graphql路径的请求转发到本地127.0.0.1:5000的postgraphile服务即可。注意postgraphile要绑定127.0.0.1地址,不要绑定0.0.0.0避免本地端口被意外扫描。
以Express搭配http-proxy-middleware为例:
const { createProxyMiddleware } = require('http-proxy-middleware'); // 新增graphql路径代理规则 app.use('/graphql', createProxyMiddleware({ target: 'http://127.0.0.1:5000', changeOrigin: true, }));
验证方式
重新部署后先查看Heroku应用日志,确认对外服务的进程绑定的是PORT环境变量对应的动态端口(一般为10000-60000区间的随机值),直接访问不带端口号的https://appname.herokuapp.com/graphql测试即可,不需要在URL中拼接任何自定义端口。
内容的提问来源于stack exchange,提问作者LEOSUNZ

