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

# !/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