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

TypeScript键盘输入无法被Flask服务接收问题排查及调试求助

跨语言键盘输入交互问题排查与调试技巧

我正在开发一个简单程序,实现将TypeScript(React)捕获的WASD键或方向键输入发送到独立的Python后端。目前按下按键时,Python终端仅返回如下日志:

127.0.0.1 - - [08/Mar/2023 22:32:14] "OPTIONS /key HTTP/1.1" 200 -

不确定数据是否正确发送和接收,首次尝试这类跨语言开发,希望找出问题并获取相关调试技巧。相关代码如下:

receive.py

from flask import Flask, request

app = Flask(__name__)

@app.route('/key', methods=['POST'])
def handle_key_data():
    data = request.json
    key = data['key']
    is_pressed = data['isPressed']
    print(f"Received {key} key {'down' if is_pressed else 'up'} event")
    return 'Success'

if __name__ == '__main__':
    app.run(port=5000, debug=True)

App.tsx

import React, { useState, useEffect } from "react";
import axios from "axios";
import "./App.css";

const apiUrl = "http://localhost:5000"; // API URL

const isValidKey = (key: string) => {
  return (
    ["W", "A", "S", "D"].indexOf(key.toUpperCase()) !== -1 ||
    ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].indexOf(key) !== -1
  );
};

const App = () => {
  const [inputValue, setInputValue] = useState("");
  const [arrowValue, setArrowValue] = useState("");

  const handleKeyDown = (event: KeyboardEvent) => {
    if (isValidKey(event.key)) {
      sendData(event.key, true); // Send data when key is first pressed down
      if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].indexOf(event.key) !== -1) {
        setArrowValue(event.key);
      } else {
        setInputValue(event.key);
      }
    }
  };

  const handleKeyUp = (event: KeyboardEvent) => {
    if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].indexOf(event.key) !== -1) {
      setArrowValue("");
    } else {
      setInputValue("");
    }
    sendData(event.key, false); // Send data when key is released
  };

  useEffect(() => {
    window.addEventListener("keydown", handleKeyDown);
    window.addEventListener("keyup", handleKeyUp);

    return () => {
      window.removeEventListener("keydown", handleKeyDown);
      window.removeEventListener("keyup", handleKeyUp);
    };
  }, []);

  function sendData(key: string, isPressed: boolean) {
    const data = JSON.stringify({
      key: key,
      isPressed: isPressed
    });
    axios
      .post(`${apiUrl}/key`, data, { 
        headers: { 'Content-Type': 'application/json' }
      })
      .then((response) => {
        console.log("Data sent successfully");
      })
      .catch((error) => {
        console.error("Error sending data:", error);
      });
  }
  

  return (
    <div>
      <p>
        Press any of the following keys: W, A, S, D, ArrowUp, ArrowDown, ArrowLeft, ArrowRight
      </p>
      {(inputValue !== "" || arrowValue !== "") && (
        <p>
          You are holding down: {inputValue}
          {arrowValue !== "" ? ` + ${arrowValue}` : ""}
        </p>
      )}
    </div>
  );
};

export default App;

问题原因分析

你看到的OPTIONS请求是浏览器的跨域资源共享(CORS)预检请求。当前端页面和后端API不在同一域名/端口时,浏览器会先发送OPTIONS请求确认后端是否允许跨域请求,而你的Flask后端没有配置CORS支持,导致浏览器在预检后拦截了实际的POST请求,所以后端永远不会执行handle_key_data函数的逻辑。

另外,你的sendData函数手动用JSON.stringify序列化数据,虽然能工作,但axios支持直接传入JavaScript对象,它会自动处理序列化和Content-Type设置,这样更简洁。

修复方案

1. 给Flask后端添加CORS支持

安装flask-cors包:

pip install flask-cors

修改receive.py,添加CORS配置:

from flask import Flask, request
from flask_cors import CORS  # 导入CORS

app = Flask(__name__)
CORS(app)  # 全局启用CORS,允许所有来源的请求

@app.route('/key', methods=['POST'])
def handle_key_data():
    data = request.json
    key = data['key']
    is_pressed = data['isPressed']
    print(f"Received {key} key {'down' if is_pressed else 'up'} event")
    return 'Success'

if __name__ == '__main__':
    app.run(port=5000, debug=True)

如果需要更严格的控制,可以指定允许的来源:

CORS(app, origins="http://localhost:3000")  # 假设前端运行在3000端口

2. 优化前端sendData函数

去掉手动的JSON.stringify,直接传入对象:

function sendData(key: string, isPressed: boolean) {
  axios
    .post(`${apiUrl}/key`, { key, isPressed })
    .then((response) => {
      console.log("Data sent successfully");
    })
    .catch((error) => {
      console.error("Error sending data:", error);
    });
}

axios会自动设置Content-Type: application/json并序列化对象,避免手动处理可能出现的错误。

跨语言交互调试技巧

前端调试

  • 浏览器控制台:打开开发者工具(F12)的「网络」标签,查看所有请求的状态、请求头、响应内容。如果POST请求失败,这里会显示具体的错误原因(比如CORS错误)。
  • 日志输出:在sendData的then和catch块中添加详细日志,确认请求是否成功发送,以及错误信息。
  • 模拟请求:用浏览器控制台直接调用sendData函数,比如sendData("W", true),测试是否能正常发送请求。

后端调试

  • 打印完整请求信息:在Flask的路由函数中添加日志,打印请求方法、请求头、请求数据,确认是否收到请求:
    @app.route('/key', methods=['POST', 'OPTIONS'])
    def handle_key_data():
        print(f"Request method: {request.method}")
        print(f"Request headers: {dict(request.headers)}")
        if request.method == 'POST':
            data = request.json
            print(f"Received data: {data}")
            key = data['key']
            is_pressed = data['isPressed']
            print(f"Received {key} key {'down' if is_pressed else 'up'} event")
            return 'Success'
        return '', 200  # 处理OPTIONS请求
    
  • 独立测试接口:用curl直接发送POST请求到http://localhost:5000/key,测试后端逻辑是否正常工作:
    curl -X POST -H "Content-Type: application/json" -d '{"key":"W", "isPressed":true}' http://localhost:5000/key
    
  • 开启Flask调试模式:保持debug=True,后端代码修改后会自动重启,并且会显示详细的错误堆栈信息。

通用技巧

  • 分步验证:先确保后端接口单独测试正常,再测试前端发送请求的逻辑,逐步排查问题。
  • 抓包工具:使用Wireshark或Charles等工具捕获网络请求,查看请求的完整内容,确认数据是否正确传输。
  • 版本兼容:检查axios、Flask等依赖的版本,避免因版本不兼容导致的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 15:19:57