fastapi: 存在httpbasic验证时Json返回需要增加headers
一,例子
当你在 FastAPI 中触发一个 401 异常时,
浏览器到底要不要弹出登录框,只取决于响应头(Headers)里有没有 WWW-Authenticate 字段,
而跟响应体(Body)是 JSON、纯文本还是 HTML 页面没有任何关系。
代码:
# --- 状况 A:如果是 API 子应用的请求,一律返回 JSON ---
if path.startswith("/api"):
status_code = err_data['status_code']
content = {"data": {}, "msg": err_data['detail'], "code": err_data['status_code']},
if status_code == 401:
headers = {"WWW-Authenticate": 'Basic realm="ApiPortal"'}
return JSONResponse(
status_code=err_data['status_code'],
content=content,
headers=headers,
)
else:
return JSONResponse(
status_code=err_data['status_code'],
content=content,
)
二,api子应用和admin都添加了httpbasic验证的情况
两处有httpbasic的情况要添加realm进行区分:
代码:
security = HTTPBasic(realm="ApiPortal")
# 初始化 Basic 认证组件
security = HTTPBasic(realm="AdminPortal")
处理异常时返回的代码:
# 返回异常信息,根据子应用和是否ajax分别进行处理,管理后非ajax请求,跳到错误页面
def response_exception(request: Request,err_data):
path = request.url.path
# --- 状况 A:如果是 API 子应用的请求,一律返回 JSON ---
if path.startswith("/api"):
status_code = err_data['status_code']
content = {"data": {}, "msg": err_data['detail'], "code": err_data['status_code']},
if status_code == 401:
headers = {"WWW-Authenticate": 'Basic realm="ApiPortal"'}
return JSONResponse(
status_code=err_data['status_code'],
content=content,
headers=headers,
)
else:
return JSONResponse(
status_code=err_data['status_code'],
content=content,
)
# --- 状况 B:如果是 Admin 子应用的请求,需要分情况讨论 ---
elif path.startswith("/admin"):
accept_header = request.headers.get("accept", "")
requested_with = request.headers.get("x-requested-with", "")
# 判断是否为 Ajax 请求:
# 1. 检查 X-Requested-With 是否为 XMLHttpRequest (传统 Ajax)
# 2. 或者检查 Accept 头是否更倾向于接收 JSON (现代 fetch/axios 请求)
is_ajax = (
requested_with.lower() == "xmlhttprequest" or
("application/json" in accept_header and "text/html" not in accept_header)
)
if is_ajax:
content={"data": {}, "msg": err_data['detail'], "code": err_data['status_code']}
if err_data['status_code'] == 401:
headers = {"WWW-Authenticate": 'Basic realm="AdminPortal"'}
return JSONResponse(
status_code=err_data['status_code'],
content=content,
headers=headers,
)
else:
return JSONResponse(
status_code=err_data['status_code'],
content=content,
)
else:
# 传统的浏览器地址栏直接访问或表单提交出错 -> 渲染精美的错误 HTML 页面
# 传入 request 和 错误信息 供模板渲染
return templates.TemplateResponse(
name="error/error.html",
context={"request": request, "status_code": err_data['status_code'], "detail": err_data['detail']},
status_code=err_data['status_code'],
headers={"WWW-Authenticate": 'Basic realm="AdminPortal"'},
request=request,
)
浙公网安备 33010602011771号