间隔数小时首次调用Django REST Framework接口失败,刷新后恢复正常
问题原因
- Heroku免费dyno冷启动休眠机制:Heroku免费套餐的dyno实例在连续30分钟无入站请求时会自动进入休眠状态以节省资源。首次触发请求时需要完成实例启动、服务加载、数据库连接初始化的完整流程,耗时通常在3~10秒,远超前端默认的请求超时阈值,导致首次请求报错,唤醒后实例只要有请求就不会休眠,所以后续访问均正常。
- axios实例默认配置缺失:当前的
axiosInstance没有配置适配冷启动场景的超时阈值和失败重试逻辑,首次冷启动请求响应超时后直接抛出错误,没有兜底机制。 - Heroku免费Postgres空闲连接回收:免费版Postgres会自动回收长时间空闲的数据库连接,首次请求时需要重新建立数据库连接,叠加服务启动耗时进一步拉长请求响应时间,加剧超时概率。
解决方案
- 调整前端axios配置,增加超时时间和重试逻辑:给
axiosInstance配置更长的超时时间,同时添加请求失败重试逻辑,针对超时、502/503类服务不可用错误自动重试2~3次,适配冷启动场景,示例代码如下:
// 初始化axios实例 const axiosInstance = axios.create({ baseURL: 'https://projectname.herokuapp.com/', timeout: 15000, // 超时时间调整为15秒适配冷启动耗时 }) // 添加响应拦截器实现自动重试 axiosInstance.interceptors.response.use(undefined, async (err) => { const { config, response: { status } = {} } = err // 仅对GET请求、超时、502/503错误做最多1次重试 if (config && !config.__retryCount && config.method === 'get' && (err.code === 'ECONNABORTED' || status === 502 || status === 503)) { config.__retryCount = 1 // 延迟2秒重试,等待服务完成唤醒 await new Promise(resolve => setTimeout(resolve, 2000)) return axiosInstance(config) } return Promise.reject(err) })
- 给接口逻辑补充错误捕获和状态提示:给
fetchArticles方法添加catch分支,首次请求失败时可展示加载中提示,避免页面无响应,示例代码如下:
const fetchArticles = () => { var url = match.params.category ? `articles/?category=${match.params.category}&dash`:"articles/?category&dash" axiosInstance.get(url) .then((res) => { setArticles(res.data.reverse()) }) .catch((err) => { // 可在此处添加加载提示、手动重试触发逻辑 }) }
- 避免dyno休眠:可在服务端新增轻量健康检查接口,每25分钟定时调用一次该接口,保持dyno始终处于运行状态,避免冷启动。
- 升级Heroku付费套餐:付费版dyno没有休眠限制,可彻底解决冷启动问题。
内容的提问来源于stack exchange,提问作者Been-H
相关产品推荐
相关产品推荐

