FastAPI如何类似Flask request.args.get()获取查询参数并修复报错
FastAPI版本经纬度测距接口修复方案
你的代码报错、模板渲染失败是以下几个原因导致的,对应修复即可:
1. 查询参数获取逻辑错误
FastAPI实现和Flask request.args.get()等效的查询参数读取有两种写法:
- 推荐写法:直接在路由函数的入参位置声明和查询参数同名的变量,FastAPI会自动完成URL参数解析、类型转换,还支持默认值配置
- 兼容Flask写法:通过
request.query_params.get("参数名")读取,用法和Flask的request.args.get()完全一致
你原来的代码中没有定义Latitude1、Longitude1等四个经纬度变量就直接传入函数,所以会触发变量未定义的报错。
2. 模板渲染失败的核心原因
- 缺失必要依赖导入:代码没有导入
HTMLResponse、Jinja2Templates、Nominatim、json等依赖模块,运行时会直接抛出导入错误 - 模板上下文传参缺失:原Flask代码渲染结果页时传入了
data变量,你写的FastAPI代码没有把计算得到的data放到模板上下文中,模板读取不到变量就会渲染报错 - 工具函数无有效返回值:原Flask代码的
Travel_distance函数没有显式return结果,默认返回None,导致result == 0的无结果分支永远无法触发,遇到接口请求失败、地理编码失败的场景会直接抛异常 - 无效语句:把
!pip install这类终端执行的shell命令写在了Python代码里,会触发语法错误
修复后可直接运行的完整代码
# 先在终端执行依赖安装:pip install fastapi uvicorn requests geopy jinja2 nest-asyncio import json import requests import uvicorn import nest_asyncio from fastapi import FastAPI, Request from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates from geopy.geocoders import Nominatim app = FastAPI() # 模板目录配置和原Flask逻辑保持一致,读取当前目录下的模板文件 templates = Jinja2Templates(directory="./") @app.get("/", response_class=HTMLResponse) async def home(request: Request): return templates.TemplateResponse( "For_putting_lat_lon.html", {"request": request} ) @app.get("/distance", response_class=HTMLResponse) async def check( request: Request, # 自动解析URL查询参数,和Flask request.args.get效果一致 Latitude1: str | None = None, Latitude2: str | None = None, Longitude1: str | None = None, Longitude2: str | None = None ): # 如果要完全沿用Flask的参数读取习惯,可注释上面的参数声明,改用下面4行代码 # Latitude1 = request.query_params.get("Latitude1") # Latitude2 = request.query_params.get("Latitude2") # Longitude1 = request.query_params.get("Longitude1") # Longitude2 = request.query_params.get("Longitude2") # 参数不全直接返回无可用结果页 if not all([Latitude1, Latitude2, Longitude1, Longitude2]): return templates.TemplateResponse("noavailable.html", {"request": request}) data = [] result = Travel_distance(Latitude1, Longitude1, Latitude2, Longitude2, data) if result == 0: return templates.TemplateResponse("noavailable.html", {"request": request}) # 必须将计算得到的data传入模板上下文,否则模板无法读取数据 return templates.TemplateResponse( "For_posting_lat_lon.html", {"request": request, "data": data} ) def Travel_distance(Latitude1, Longitude1, Latitude2, Longitude2, data): try: geolocator = Nominatim(user_agent="geoapiExercises") location_name1 = geolocator.geocode(f"{Latitude1}, {Longitude1}") location_name2 = geolocator.geocode(f"{Latitude2}, {Longitude2}") # 地理编码失败返回0,触发无结果页 if not location_name1 or not location_name2: return 0 req = requests.get( f"http://router.project-osrm.org/route/v1/drive/{Longitude1},{Latitude1};{Longitude2},{Latitude2}?overview=false", timeout=10 ) # OSRM接口请求失败返回0 if req.status_code != 200: return 0 route_1 = json.loads(req.content) # 路由数据为空返回0 if not route_1.get("routes") or len(route_1["routes"]) == 0: return 0 df_s = [ location_name1, location_name2, str(route_1['routes'][0]['distance'] / 1000) ] data.append(df_s) return 1 except Exception as e: print(f"距离计算出错:{str(e)}") return 0 if __name__ == "__main__": nest_asyncio.apply() uvicorn.run(app, port=8000)
补充说明
- FastAPI的Jinja2模板渲染要求必须在上下文中传入
request对象,其余模板变量的传参逻辑和Flask的render_template完全一致,只需要把变量以键值对形式写到返回的字典里即可 - 修复版新增了异常捕获逻辑,遇到第三方接口超时、经纬度无效等场景不会直接抛出500错误,会正常返回无可用结果页面,稳定性比原Flask版本更高
内容的提问来源于stack exchange,提问作者Pooja Rajendra Prasad Tripathi
相关产品推荐
相关产品推荐

