Flask+PostgreSQL REST API重构后遇404错误,求解决方案
解决Flask通用API路由的404与功能问题
嘿,我来帮你梳理下重构代码里的问题,几个小调整就能让你的通用API正常工作啦!
主要问题与修改点:
1. 路由定义错误(直接导致404)
你用了${table_name}这种非Flask规范的路由变量写法,Flask要求路由变量用<变量名>的格式。另外你的访问路径/api/stat_data是把表别名放在URL路径里,但原重构代码却用查询参数来获取,逻辑完全不匹配。
修改方案:把路由改成接收路径变量,对应你dico里的键:
@app.route('/api/<table_alias>', methods=("POST", "GET")) def get_table_json(table_alias): # 后续用table_alias去匹配dico里的真实表名
2. SQL查询字符串格式化错误
get_table函数里的SQL语句没有正确替换变量,${table_name}是模板语法,Python根本不识别,要改用f-string或者.format()来处理变量替换:
def get_table(table_name): # 用f-string替换变量,注意PostgreSQL的表名如果有大小写需要加双引号 query = f'select * from "{table_name}"' return pd.read_sql_query(query, con=engine)
3. 变量名不匹配导致报错
你在函数里把查询结果赋值给了data_generique,但return的时候写的是df_generique.to_json(),这会直接抛出NameError,必须统一变量名:
data_generique = get_table(dico[table_alias]) return data_generique.to_json()
4. 参数逻辑与异常处理优化
既然用了路径变量,就不需要再用request.args.get('table')了,直接用路由传入的table_alias去匹配你的dico映射即可。另外最好加个别名合法性校验,防止传入不存在的别名导致KeyError:
def get_table_json(table_alias): if table_alias not in dico: return {"error": "无效的表别名"}, 400 # 再加个异常捕获,避免数据库查询报错直接崩掉服务 try: data_generique = get_table(dico[table_alias]) return data_generique.to_json() except Exception as e: return {"error": f"查询失败:{str(e)}"}, 500
修改后的完整代码:
from flask import Flask, request import pandas as pd # 假设你的engine已经正确初始化(比如用sqlalchemy创建) # engine = create_engine(...) app = Flask(__name__) dico = { 'stat_data': "srcstatistiquedata", 'stat_suppr': "srcstatistiquesuppression", 'en_tete': "srcentete" } def get_table(table_name): query = f'select * from "{table_name}"' return pd.read_sql_query(query, con=engine) @app.route('/api/<table_alias>', methods=("POST", "GET")) def get_table_json(table_alias): if table_alias not in dico: return {"error": "无效的表别名"}, 400 try: data_generique = get_table(dico[table_alias]) return data_generique.to_json() except Exception as e: return {"error": f"查询失败:{str(e)}"}, 500 if __name__ == '__main__': app.run(debug=True)
补充说明:
- 现在你访问
http://127.0.0.1:5000/api/stat_data就能拿到srcstatistiquedata表的数据了,其他别名(stat_suppr、en_tete)同理。 - 关于SQL注入:因为你用了
dico做白名单映射,只允许传入预定义的别名,不会直接把用户输入拼到SQL里,所以相对安全。如果直接用用户输入作为表名,会有很大的注入风险,一定要避免。
内容的提问来源于stack exchange,提问作者userHG
相关产品推荐
相关产品推荐

