You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Heroku部署带登录Flask应用控树莓派GPIO,连续发MQTT信号不稳定如何解决

可能的原因

  • SECRET_KEY随机生成导致会话失效:代码中使用os.urandom(24)动态生成SECRET_KEY和SALT,Heroku环境下dyno重启、冷启动、或多实例部署时,会生成新的密钥,导致用户登录会话失效,@login_required装饰器直接拦截/sendMovement请求。本地环境是单实例长期运行,移除登录后无需校验会话,因此不会触发该问题,完全匹配你给出的异常/正常场景。
  • 前端同步Ajax阻塞请求:前端Ajax配置了async: false同步请求,频繁发送时会阻塞浏览器请求队列,叠加Heroku的网络延迟,容易出现请求丢包、超时的情况。
  • MQTT连接频繁重建:如果三个GPIO_Control_SendMQTT_*.py的send()方法每次调用都会新建MQTT连接、走TLS认证再销毁连接,频繁调用时会出现连接建立失败,还可能触发CloudMQTT的连接频率限制,导致消息丢失。
  • 接口响应慢触发Heroku超时:sendMovement接口处理完MQTT逻辑后还要渲染完整的index.html,响应耗时变长,频繁请求时排队容易触发Heroku默认30秒的请求超时限制,请求被平台强制中断。

解决方案

  1. 固定SECRET_KEY配置
    将密钥改为从环境变量读取,避免动态生成:
# 替换原随机生成密钥的代码段
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY')
app.secret_key = app.config['SECRET_KEY']
SALT = os.getenv('SALT')

随后进入Heroku后台的【Settings】->【Config Vars】,添加SECRET_KEY和SALT两个变量,值为自定义的随机长字符串即可,保证所有实例、重启后密钥统一,会话不会失效。

  1. 优化前端请求逻辑
    把同步Ajax改为异步,新增请求锁避免频繁点击重复提交:
let isSending = false; // 全局请求锁
function ajaxSend(fData, urlFlask) {
    if(isSending) return;
    isSending = true;
    $.ajax({
        url: urlFlask,
        type: 'POST',
        async: true, // 改为异步请求
        data: fData,
        contentType: false,
        processData: false,
        success: function(data, dataType) {
            console.log('Success', data);
        },
        error: function(XMLHttpRequest, textStatus, errorThrown) {
            console.log('Error : ' + errorThrown);
        },
        complete: function() {
            isSending = false; // 请求完成释放锁
        }
    });
}
  1. 复用MQTT长连接
    调整MQTT工具代码逻辑,全局复用同一个MQTT长连接,不要每次发消息都重建连接,减少连接开销同时避免触发CloudMQTT的频率限制。

  2. 简化接口响应
    将sendMovement接口改为返回JSON,无需渲染HTML模板,降低响应耗时:

from flask import jsonify

@app.route('/sendMovement', methods=['POST'])
@login_required
def sendMovement():
    PostMonement = str(request.form['Monement'])  
    if PostMonement == "move_one":
        GPIO_Control_SendMQTT_One.send()
    elif PostMonement == "move_two":
        GPIO_Control_SendMQTT_Two.send()
    elif PostMonement == "move_three":
        GPIO_Control_SendMQTT_Three.send()
    return jsonify({"status": "success"})

内容的提问来源于stack exchange,提问作者hekatonkeiru

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 16:45:04