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代码:
- 安装依赖:
pip install paho-mqtt - 在路由的
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
相关产品推荐
相关产品推荐

