You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
159 lines
5.2 KiB
159 lines
5.2 KiB
# !/usr/bin/env python3
|
|
# -*- encoding : utf-8 -*-
|
|
# @Filename : __init__.py
|
|
# @Software : VSCode
|
|
# @Datetime : 2021/11/03 16:59:57
|
|
# @Author : leo liu
|
|
# @Version : 1.0
|
|
# @Description :
|
|
|
|
import traceback
|
|
from fastapi import FastAPI, Request, status, HTTPException
|
|
from fastapi.encoders import jsonable_encoder
|
|
from fastapi.responses import JSONResponse
|
|
from fastapi.exceptions import RequestValidationError
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
|
|
# from slowapi import Limiter
|
|
# from slowapi.util import get_remote_address
|
|
# from slowapi.middleware import SlowAPIMiddleware
|
|
|
|
from api.v1 import api_v1
|
|
from extensions import logger
|
|
from core.settings import config
|
|
from utils.custom_exc import PostParamsError, TokenAuthError # 自定义异常
|
|
|
|
# swigger 文档分类 https://fastapi.tiangolo.com/tutorial/metadata/
|
|
tags_metadata = [
|
|
{
|
|
"name": "首页",
|
|
"description": "数据API",
|
|
},
|
|
]
|
|
|
|
def create_app():
|
|
app = FastAPI(
|
|
title="Chatmed",
|
|
description="",
|
|
version="0.0.1",
|
|
docs_url=config.DOCS_URL,
|
|
openapi_url=config.OPENAPI_URL,
|
|
redoc_url=config.REDOC_URL,
|
|
openapi_tags=tags_metadata
|
|
)
|
|
|
|
app.include_router(
|
|
api_v1,
|
|
prefix="/api/v1",
|
|
)
|
|
|
|
register_exception(app) # 注册捕获异常信息
|
|
register_cors(app) # 跨域设置
|
|
register_middleware(app)
|
|
|
|
return app
|
|
|
|
def register_exception(app: FastAPI):
|
|
"""
|
|
全局异常捕获
|
|
:param app:
|
|
:return:
|
|
"""
|
|
|
|
# 捕获自定义异常
|
|
@app.exception_handler(PostParamsError)
|
|
async def query_params_exception_handler(request: Request, exc: PostParamsError):
|
|
"""
|
|
捕获 自定义抛出的异常
|
|
:param request:
|
|
:param exc:
|
|
:return:
|
|
"""
|
|
logger.error(f"参数查询异常\nURL:{request.url}\nHeaders:{request.headers}\n{traceback.format_exc()}")
|
|
return JSONResponse(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
content={"code": 400, "data": {"tip": exc.err_desc}, "message": "fail"},
|
|
)
|
|
|
|
@app.exception_handler(TokenAuthError)
|
|
async def token_exception_handler(request: Request, exc: TokenAuthError):
|
|
logger.error(f"参数查询异常\nURL:{request.url}\nHeaders:{request.headers}\n{traceback.format_exc()}")
|
|
return JSONResponse(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
content={"code": 400, "data": None, "message": exc.err_desc},
|
|
)
|
|
|
|
# 捕获参数 验证错误
|
|
@app.exception_handler(RequestValidationError)
|
|
async def validation_exception_handler(request: Request, exc: RequestValidationError):
|
|
"""
|
|
捕获请求参数 验证错误
|
|
:param request:
|
|
:param exc:
|
|
:return:
|
|
"""
|
|
logger.error(f"参数错误\nURL:{request.url}\nHeaders:{request.headers}\n{traceback.format_exc()}")
|
|
return JSONResponse(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
content=jsonable_encoder({"code": 400, "data": {"tip": exc.errors()}, "body": exc.body, "message": "fail"}),
|
|
)
|
|
|
|
# 捕获全部异常
|
|
@app.exception_handler(Exception)
|
|
async def all_exception_handler(request: Request, exc: Exception):
|
|
logger.error(f"全局异常\nURL:{request.url}\nHeaders:{request.headers}\n{traceback.format_exc()}")
|
|
return JSONResponse(
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
content={"code": 500, "data": {"tip": "服务器错误"}, "message": "fail"},
|
|
)
|
|
|
|
# 捕获调用超限异常
|
|
# @app.exception_handler(HTTPException)
|
|
# async def rate_limit_handler(request, exc):
|
|
# if exc.status_code == 429:
|
|
# return JSONResponse(status_code=status.HTTP_429_TOO_MANY_REQUESTS,
|
|
# content={"code": 429, "data": "我还在处理您的问题,请稍后再试!", "message": "to many requests"},)
|
|
# return JSONResponse(
|
|
# status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
# content={"code": 500, "data": {"tip": "服务器错误"}, "message": "fail"},
|
|
# )
|
|
|
|
def register_cors(app: FastAPI):
|
|
"""
|
|
支持跨域
|
|
|
|
貌似发现了一个bug
|
|
https://github.com/tiangolo/fastapi/issues/133
|
|
|
|
:param app:
|
|
:return:
|
|
"""
|
|
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
# allow_origins=['http://localhost:8081'], # 有效, 但是本地vue端口一直在变化, 接口给其他人用也不一定是这个端口
|
|
# allow_origins=['*'], # 无效 bug allow_origins=['http://localhost:8081']
|
|
allow_origin_regex='https?://.*', # 改成用正则就行了
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
def register_middleware(app: FastAPI):
|
|
"""
|
|
请求响应拦截 hook
|
|
|
|
https://fastapi.tiangolo.com/tutorial/middleware/
|
|
:param app:
|
|
:return:
|
|
"""
|
|
|
|
@app.middleware("http")
|
|
async def logger_request(request: Request, call_next):
|
|
# https://stackoverflow.com/questions/60098005/fastapi-starlette-get-client-real-ip
|
|
logger.info(f"访问记录:{request.method} url:{request.url}\nheaders:{request.headers.get('user-agent')}"
|
|
f"\nIP:{request.client.host}")
|
|
|
|
response = await call_next(request)
|
|
|
|
return response |