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

Flask与JavaScript交互报错:POST请求400 Bad Request求助

解决Actuator按钮点击时的400错误及MQTT消息发送问题

问题场景

点击Actuator开关按钮时,本应向微控制器发送激活/关闭消息,但触发400 Bad Request错误。

错误日志

Enviando comando al actuador 3: 1
1:954 Body being sent: {"mensaje":"1"}
1:955 1
1:956 
       
       POST http://127.0.0.1:5001/enviar_comando_actuador/3 400 (BAD REQUEST)
toggleSwitch @ 1:956
onclick @ 1:370
1:963 Response status: 400
1:979 Error al enviar comando al actuador: Error: HTTP status 400
    at 1:965:19

现有代码

HTML代码

{% for actuador in actuadores %}
  <div class="elemento">
    {% if actuador.tipo == 'switch' %}
    <button class="switch-button" id="switch_{{ actuador.id }}" 
    data-actuador-id="{{ actuador.id }}" 
    data-state="{{ actuador.estado_actual }}" 
    onclick="toggleSwitch(this)"
    style="background-color: {{ 'green' if actuador.estado_actual == '1' else 'red' }}">
        <span>{{ actuador.nombre }}</span><br>
        <span>{{ actuador.tipo }}</span><br>
        <span>{{ actuador.ubicacion }}</span>
    </button>

    {% elif actuador.tipo == 'altavoz' %}
    <button class="switch-button" id="switch_{{ actuador.id }}" data-actuador-id="{{ actuador.id }}" data-state="" onclick="">
        <span>{{ actuador.nombre }}</span><br>
        <span>{{ actuador.tipo }}</span><br>
        <span>{{ actuador.ubicacion }}</span>
    </button>
    
    {% endif %}
    <div class="menu-button" onclick="showMenu({{ actuador.id }})">...</div>
  </div>
{% else %}
  <p>No hay actuadores agregados. Por favor, agregue uno.</p>
{% endfor %}

JavaScript代码

function toggleSwitch(buttonElement) {
    const actuadorId = buttonElement.dataset.actuadorId;
    let currentState = buttonElement.dataset.state;
    const newState = currentState === '1' ? '0' : '1';

    console.log(`Enviando comando al actuador ${actuadorId}: ${newState}`);
    console.log(`Body being sent:`, JSON.stringify({ mensaje: newState }));
    console.log(newState)
    fetch(`/enviar_comando_actuador/${actuadorId}`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ mensaje: newState })
        
    })
    .then(response => {
        console.log('Response status:', response.status);
        if (!response.ok) {
            throw new Error(`HTTP status ${response.status}`);
        }
        return response.json();
    })
    .then(data => {
        console.log('Respuesta del servidor:', data);
        if (data.success) {
            buttonElement.dataset.state = newState;
            buttonElement.style.backgroundColor = newState === '1' ? 'green' : 'red';
        } else {
            console.error('Error al procesar el comando:', data.message);
        }
    })
    .catch(error => {
        console.error('Error al enviar comando al actuador:', error);
    });
}

Flask路由代码

@main.route('/enviar_comando_actuador/<int:actuador_id>', methods=['POST'])
@login_required
def enviar_comando_actuador(actuador_id):
    if not request.is_json:
        print("Error: No JSON received")
        return jsonify({'success': False, 'message': 'Expected JSON content'}), 400

    data = request.get_json()
    comando = data.get('mensaje')
    print(f"Received JSON: {data}")  # Imprimir los datos JSON recibidos
    print(f"Received command for actuator {actuador_id}: {comando}")

    if comando not in ['0', '1']:
        print("Error: Invalid command value")
        return jsonify({'success': False, 'message': 'Invalid command value'}), 400

    try:
        actuador = Actuador.query.get(actuador_id)  # Use get() instead of get_or_404()
        if not actuador:
            print(f"Actuator with ID {actuador_id} not found")
            return jsonify({'success': False, 'message': 'Actuator not found'}), 404  # Return 404 for missing actuator
        print(f"Command {comando} will be sent to actuator {actuador_id}")
        # Simular el envío de comando al hardware aquí si es necesario
        return jsonify({'success': True, 'message': 'Comando enviado correctamente.', 'estado': comando})
    except Exception as e:
        print(f"Error while processing command: {str(e)}")
        return jsonify({'success': False, 'message': 'Error al enviar comando.', 'error': str(e)}), 500

排查与修复方案

1. 解决CSRF保护导致的400错误

如果你的Flask应用启用了Flask-WTF的CSRF保护,POST请求必须携带CSRF Token,否则会被拦截返回400。修改JS代码:

  • 添加CSRF Token获取函数:
    function getCookie(name) {
        let cookieValue = null;
        if (document.cookie && document.cookie !== '') {
            const cookies = document.cookie.split(';');
            for (let i = 0; i < cookies.length; i++) {
                const cookie = cookies[i].trim();
                if (cookie.substring(0, name.length + 1) === (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    
  • 更新fetch的headers配置:
    headers: {
      'Content-Type': 'application/json',
      'X-CSRFToken': getCookie('csrf_token')
    }
    

2. 修正状态值类型不匹配问题

如果actuador.estado_actual是整数类型(而非字符串),JS中currentState === '1'的判断会出错,导致发送的状态值不符合预期:

  • 方案1:在HTML模板中强制转为字符串:
    data-state="{{ str(actuador.estado_actual) }}"
    
  • 方案2:在JS中转换类型后判断:
    let currentState = String(buttonElement.dataset.state);
    

3. 补充MQTT实际发送逻辑

当前Flask路由仅模拟发送,需添加真实MQTT代码:

  1. 安装依赖:pip install paho-mqtt
  2. 在路由的try块中添加MQTT发送逻辑:
    import paho.mqtt.client as mqtt
    
    # 替换为你的MQTT Broker地址和端口
    client = mqtt.Client()
    client.connect("127.0.0.1", 1883, 60)
    # 发布消息到对应主题
    client.publish(f"dispositivos/actuadores/{actuador_id}", comando)
    client.disconnect()
    

4. 调试技巧

  • 查看Flask控制台输出:如果打印Error: No JSON received,说明请求头或Payload格式错误;如果打印Received JSON,则JSON接收正常,排查后续逻辑。
  • 用浏览器开发者工具的Network标签,检查POST请求的Request Headers是否包含Content-Type: application/json,以及Request Payload是否为{"mensaje":"1"}或{"mensaje":"0"}。

内容的提问来源于stack exchange,提问作者Ismael Jiménez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 17:54:53