【最快入门】一篇文章学会Python最快框架fastapi

目录

一、简介

二、quick start

2.1 简单案例

安装依赖

编写代码

运行服务器

测试

2.2 交互式 API 文档

三、路径操作

3.1 路径操作装饰器

3.2 include_router

四、请求与响应

4.1 路径参数

(1)基本用法

(2)有类型的路径参数

(3)注意顺序

4.2 查询参数(请求参数)

4.3 请求体数据

4.4 form表单数据

4.5 文件上传

4.6 Reqeust对象

4.7 请求静态文件

4.8 响应模型相关参数

(1)response_model

(2)response_model_exclude_unset

(3)INCLUDE和EXCLUDE

五、ORM操作

5.1 创建模型

6.2、aerich迁移工具

1. 初始化配置,只需要使用一次

2. 初始化数据库,一般情况下只用一次

3. 更新模型并进行迁移

4. 重新执行迁移,写入数据库

5. 回到上一个版本

6. 查看历史迁移记录

6.3 选课系统接口开发

六、中间件与CORS

6.1 中间件

6.2 CORS


一、简介

fastapi,一个用于构建 API 的现代、快速(高性能)的web框架。

fastapi是建立在StarlettePydantic基础上的,Pydantic是一个基于Python类型提示来定义数据验证、序列化和文档的库。Starlette是一种轻量级的ASGI框架/工具包,是构建高性能Asyncio服务的理性选择。

  • 快速:可与 NodeJS 和 Go 比肩的极高性能(归功于 StarlettePydantic),是最快的 Python web 框架之一。

  • 高效编码:提高功能开发速度约 200% 至 300%。

  • 更少bug:减少约 40% 的人为(开发者)导致错误。

  • 智能:极佳的编辑器支持。处处皆可自动补全,减少调试时间。

  • 简单:设计的易于使用和学习,阅读文档的时间更短。

  • 简短:使代码重复最小化。通过不同的参数声明实现丰富功能。

  • 健壮:生产可用级别的代码。还有自动生成的交互式文档

依赖:Python 3.6 及更高版本,FastAPI 站在以下巨人的肩膀之上。

[Starlette](https://www.starlette.io/) 负责 web 部分(Asyncio)

[Pydantic](https://pydantic-docs.helpmanual.io/) 负责数据部分(类型提示)

FastApi是站在前人肩膀上,集成了多种框架的优点的新秀框架。它出现的比较晚,2018年底才发布在github上。广泛应用于当前各种前后端分离的项目开发,测试运维自动化以及微服务的场景中。

二、quick start

2.1 简单案例

安装依赖

pip install fastapi

你还会需要一个 ASGI 服务器,生产环境可以使用 Uvicorn

pip install uvicorn

编写代码

from fastapi import FastAPI  # FastAPI 是一个为你的 API 提供了所有功能的 Python 类。

app = FastAPI()  # 这个实例将是创建你所有 API 的主要交互对象。这个 app 同样在如下命令中被 uvicorn 所引用

@app.get("/")
async def root():
    return {"message": "Hello clay"}

运行服务器

通过以下命令运行服务器:

uvicorn quickstart:app --reload

quickstart是文件名,app是代码中app = FastAPI()的名字。

也可以直接运行:

在你quickstart文件中写入如下代码:

if __name__ == '__main__':
    import uvicorn

    uvicorn.run("quickstart:app", host="127.0.0.1", port=8080, reload=True)

右键run运行即可。

测试

当我们浏览器访问http://127.0.0.1:8000/,就会获取数据。

2.2 交互式 API 文档

fastapi有着非常棒的交互式 API 文档,这一点很吸引人。

跳转到 http://127.0.0.1:8000/docs。你将会看到自动生成的交互式 API 文档。

三、路径操作

3.1 路径操作装饰器

fastapi支持各种请求方式:

@app.get()
@app.post()
@app.put()
@app.patch()
@app.delete()
@app.options()
@app.head()
@app.trace()

from fastapi import FastAPI

app = FastAPI()


@app.get("/get")
def get_test():
    return {"method": "get方法"}


@app.post("/post")
def post_test():
    return {"method": "post方法"}


@app.put("/put")
def put_test():
    return {"method": "put方法"}


@app.delete("/delete")
def delete_test():
    return {"method": "delete方法"}


if __name__ == '__main__':
    import uvicorn

    uvicorn.run("quickstart:app", host="127.0.0.1", port=8080, reload=True)

路径操作装饰器参数:

@app.post(
    "/items/{item_id}",
    # response_model=Item, # 响应的数据模型
    # status_code=status.HTTP_200_OK, # 响应的状态码
    tags=["商品"], # 接口分组名
    summary="this is summary",  # 接口的描述简介
    description="this is description", # 接口的描述详情
    response_description= "this is response_description", # 接口的响应描述详情
    deprecated=False, # 接口是否废弃了,如果True,API文档会变灰
)

3.2 include_router

我们在真实web项目中,业务很复杂,一定会用到路由分发。

main.py

from typing import Union

from fastapi import FastAPI
import uvicorn
from shop.apps.app01.urls import shop
from shop.apps.app02.urls import user

app = FastAPI()

app.include_router(shop, prefix="/shop", tags=["商城接口", ])
app.include_router(user, prefix="/user", tags=["用户中心接口", ])

if __name__ == '__main__':
    uvicorn.run("main:app", host="127.0.0.1", port=8080, reload=True)

app01/urls

from fastapi import APIRouter

shop = APIRouter()


@shop.get("/food")
def shop_food():
    return {"shop": "food"}


@shop.get("/bed")
def shop_food():
    return {"shop": "bed"}

app02/urls

from fastapi import APIRouter

user = APIRouter()


@user.post("/login")
def user_login():
    return {"user": "login"}


@user.post("/reg")
def user_reg():
    return {"user": "reg"}

四、请求与响应

4.1 路径参数

(1)基本用法

以使用与 Python 格式化字符串相同的语法来声明路径"参数"或"变量":

@app.get("/user/{user_id}")
def get_user(user_id):
    print(user_id, type(user_id))
    return {"user_id": user_id}

路径参数 user_id 的值将作为参数 user_id 传递给你的函数。

(2)有类型的路径参数

你可以使用标准的 Python 类型标注为函数中的路径参数声明类型。

@app.get("/user/{user_id}")
def get_user(user_id: int): # 这样写参数可以将传来的user_id自动转为int类型
    print(user_id, type(user_id))
    return {"user_id": user_id}

(3)注意顺序

在创建路径操作时,你会发现有些情况下路径是固定的。

比如 /users/me,我们假设它用来获取关于当前用户的数据.

然后,你还可以使用路径 /user/{username} 来通过用户名 获取关于特定用户的数据。

由于路径操作是按顺序依次运行的,你需要确保路径 /user/me 声明在路径 /user/{username}之前:

@app.get("/user/me")
async def read_user_me():
    return {"username": "the current user"}

@app.get("/user/{username}")
async def read_user(username: str):
    return {"username": username}

否则,/user/{username} 的路径还将与 /user/me 相匹配,"认为"自己正在接收一个值为 "me"username 参数。

4.2 查询参数(请求参数)

路径函数中声明不属于路径参数的其他函数参数时,它们将被自动解释为"查询字符串"参数,就是 url? 之后用&分割的 key-value 键值对。

@app.get("/jobs")
async def search_jobs(kd: str, city: Union[str, None] = None, xl: Union[str, None] = None):  # 有默认值即可选,否则必选
    if city or xl:
        return {"kd": kd, "city": city, "xl": xl}
    return {"kd": kd}

在这个例子中,函数参数 cityxl 是可选的,并且默认值为 None

自python3.5开始,PEP484为python引入了类型注解(type hints),typing的主要作用有:

  1. 类型检查,防止运行时出现参数、返回值类型不符。

  2. 作为开发文档附加说明,方便使用者调用时传入和返回参数类型。

  3. 模块加入不会影响程序的运行不会报正式的错误,pycharm支持typing检查错误时会出现黄色警告。

type hints主要是要指示函数的输入和输出的数据类型,数据类型在typing 包中,基本类型有str list dict等等,

Union 是当有多种可能的数据类型时使用,比如函数有可能根据不同情况有时返回str或返回list,那么就可以写成Union[list, str] Optional 是Union的一个简化, 当 数据类型中有可能是None时,比如有可能是str也有可能是None,则Optional[str], 相当于Union[str, None]。

4.3 请求体数据

当你需要将数据从客户端(例如浏览器)发送给 API 时,你将其作为「请求体」发送。请求体是客户端发送给 API 的数据。响应体是 API 发送给客户端的数据。

FastAPI 基于 PydanticPydantic 主要用来做类型强制检查(校验数据)。不符合类型要求就会抛出异常。

对于 API 服务,支持类型检查非常有用,会让服务更加健壮,也会加快开发速度,因为开发者再也不用自己写一行一行的做类型检查。

安装上手

pip install pydantic
from typing import Union, List, Optional
from fastapi import FastAPI
from pydantic import BaseModel, Field, ValidationError, field_validator
import uvicorn
from datetime import date


class Addr(BaseModel):
    province: str
    city: str


class User(BaseModel):
    name: str = 'root'
    age: int = Field(default=0, lt=100, gt=0)
    birth: Optional[date] = None
    friends: List[int] = []
    description: Union[str, None] = None
    addr: Optional[Addr] = None  # 类型嵌套

    @field_validator('name')
    def name_must_alpha(cls, v): # 校验name必须是字母的组合
        if not v.isalpha():
            raise ValueError('name must be alpha')
        return v


class Data(BaseModel):  # 类型嵌套
    users: List[User]


app = FastAPI()


@app.post("/data/")
async def create_data(data: Data): # 请求体参数必须符合Data类的格式
    # 添加数据库
    return data


if __name__ == '__main__':
    try:
        uvicorn.run("test:app", host="127.0.0.1", port=8080, reload=True)
    except ValidationError as e:
        print(e.json())

和声明查询参数时一样,当一个模型属性具有默认值时,它不是必需的。否则它是一个必需属性。将默认值设为 None 可使其成为可选属性。

FastAPI 会自动将定义的模型类转化为JSON Schema,Schema 成为 OpenAPI 生成模式的一部分,并显示在 API 交互文档中,查看 API 交互文档如下,该接口将接收application/json类型的参数。

FastAPI 支持同时定义 Path 参数、Query 参数和请求体参数,FastAPI 将会正确识别并获取数据。

参数在 url 中也声明了,它将被解释为 path 参数

参数是单一类型(例如int、float、str、bool等),它将被解释为 query 参数

参数类型为继承 Pydantic 模块的BaseModel类的数据模型类,则它将被解释为请求体参

4.4 form表单数据

在 OAuth2 规范的一种使用方式(密码流)中,需要将用户名、密码作为表单字段发送,而不是 JSON。

FastAPI 可以使用Form组件来接收表单数据,需要先使用pip install python-multipart命令进行安装。

pip install python-multipart
import uvicorn
from fastapi import FastAPI, Form

app = FastAPI()

# 用户注册功能
@app.post("/regin")
def regin(username: str = Form(..., max_length=16, min_length=8, regex='[a-zA-Z]'),
          password: str = Form(..., max_length=16, min_length=8, regex='[0-9]')):
    print(f"username:{username},password:{password}")
    return {"username": username}

4.5 文件上传

import uvicorn
from fastapi import FastAPI, File, UploadFile
from typing import List

app = FastAPI()

# file: bytes = File():适合小文件上传
@app.post("/files/")
async def create_file(file: bytes = File()):
    print("file:", file)
    return {"file_size": len(file)}

# 上传多个文件
@app.post("/multiFiles/")
async def create_files(files: List[bytes] = File()):
    return {"file_sizes": [len(file) for file in files]}


# file: UploadFile:适合大文件上传
@app.post("/uploadFile/")
async def create_upload_file(file: UploadFile):
    with open(f"{file.filename}", 'wb') as f:
        for chunk in iter(lambda: file.file.read(1024), b''):
            f.write(chunk)

    return {"filename": file.filename}


@app.post("/multiUploadFiles/")
async def create_upload_files(files: List[UploadFile]):
    return {"filenames": [file.filename for file in files]}



if __name__ == '__main__':
    uvicorn.run("test:app", host="127.0.0.1", port=8080, reload=True)

4.6 Reqeust对象

有些情况下我们希望能直接访问Request对象。例如我们在路径操作函数中想获取客户端的IP地址,需要在函数中声明Request类型的参数,FastAPI 就会自动传递 Request 对象给这个参数,我们就可以获取到 Request 对象及其属性信息,例如 header、url、cookie、session 等。

from urllib.request import Request

import uvicorn
from fastapi import FastAPI, Request

app = FastAPI()

@app.get("/items")
async def items(request: Request):
    return {
        "请求URL:": request.url,
        "请求ip:": request.client.host,
        "请求宿主:": request.headers.get("user-agent"),
        "cookies": request.cookies,
    }


if __name__ == '__main__':
    uvicorn.run("test:app", host="127.0.0.1", port=8080, reload=True)

4.7 请求静态文件

在 Web 开发中,需要请求很多静态资源文件(不是由服务器生成的文件),如 css/js 和图片文件等。

import uvicorn
from fastapi import FastAPI, Request
from starlette.staticfiles import StaticFiles

app = FastAPI()

app.mount("/static", StaticFiles(directory="static"))


if __name__ == '__main__':
    uvicorn.run("test:app", host="127.0.0.1", port=8080, reload=True)

当我访问http://127.0.0.1:8080/static/1.jpg就会获取到静态资源图片

4.8 响应模型相关参数

(1)response_model

前面写的这么多路径函数最终 return 的都是自定义结构的字典,FastAPI 提供了 response_model 参数,声明 return 响应体的模型。

# 路径操作
@app.post("/items/", response_model=Item)
# 路径函数
async def create_item(item: Item):
    ...

response_model 是路径操作的参数,并不是路径函数的参数哦。

FastAPI将使用response_model进行以下操作:

  • 将输出数据转换为response_model中声明的数据类型。

  • 验证数据结构和类型

  • 将输出数据限制为该model定义的

  • 添加到OpenAPI中

  • 在自动文档系统中使用。

你可以在任意的路径操作中使用 response_model 参数来声明用于响应的模型

案例:

  • 注册功能

  • 输入账号、密码、昵称、邮箱,注册成功后返回个人信息

from typing import Union

import uvicorn
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Union[str, None] = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: Union[str, None] = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn):
    return user



if __name__ == '__main__':
    uvicorn.run("test:app", host="127.0.0.1", port=8080, reload=True)

(2)response_model_exclude_unset

通过上面的例子,我们学到了如何用response_model控制响应体结构,但是如果它们实际上没有存储,则可能要从结果中忽略它们。例如,如果model在NoSQL数据库中具有很多可选属性,但是不想发送很长的JSON响应,其中包含默认值。

案例:

from typing import List, Union

import uvicorn
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: float = 10.5
    tags: List[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]



if __name__ == '__main__':
    uvicorn.run("test:app", host="127.0.0.1", port=8080, reload=True)

注意:items是模拟数据库。

这段代码的意思是当我们传item_id参数,比如foo,只有name和price两个key,如果我们不设置response_model_exclude_unset,那么会返回Item实体类所有的key,但如果我们设置了,返回的只有name和price。

不设置unset参数:

{
  "name": "Foo",
  "description": null,
  "price": 50.2,
  "tax": 10.5,
  "tags": []
}

设置unset参数:

{
  "name": "Foo",
  "price": 50.2
}

使用路径操作装饰器的 response_model 参数来定义响应模型,特别是确保私有数据被过滤掉。使用 response_model_exclude_unset 来仅返回显式设定的值。 除了response_model_exclude_unset以外,还有response_model_exclude_defaultsresponse_model_exclude_none,我们可以很直观的了解到他们的意思,不返回是默认值的字段和不返回是None的字段。

(3)INCLUDE和EXCLUDE

# response_model_exclude
@app.get("/items/{item_id}", response_model=Item, response_model_exclude={"description"}, )
async def read_item(item_id: str):
    return items[item_id]

# response_model_include  
@app.get("/items/{item_id}", response_model=Item, response_model_include={"name", "price"}, )
async def read_item(item_id: str):
    return items[item_id]

很容易理解,就是排除某个字段和只接受某个字段。

五、ORM操作

在大型的web开发中,我们肯定会用到数据库操作,那么FastAPI也支持数据库的开发,你可以用 PostgreSQL、MySQL、 SQLite Oracle 等。本文用SQLite为例。我们看下在fastapi是如何操作设计数据库的。

fastapi是一个很优秀的框架,但是缺少一个合适的orm,官方代码里面使用的是sqlalchemy,Tortoise ORM 是受 Django 启发的易于使用的异步 ORM (对象关系映射器)。

Tortoise ORM 目前支持以下数据库

  • PostgreSQL >= 9.4(使用asyncpg

  • SQLite(使用aiosqlite

  • MySQL/MariaDB(使用aiomysql或使用asyncmy

安装依赖:

pip install tortoise-orm
pip install aiomysql

5.1 创建模型

以选课系统为例:

models.py

from tortoise.models import Model
from tortoise import fields


class Clas(Model):
    name = fields.CharField(max_length=255, description='班级名称')


class Teacher(Model):
    id = fields.IntField(pk=True)
    name = fields.CharField(max_length=255, description='姓名')
    tno = fields.IntField(description='账号')
    pwd = fields.CharField(max_length=255, description='密码')


class Student(Model):
    id = fields.IntField(pk=True)
    sno = fields.IntField(description='学号')
    pwd = fields.CharField(max_length=255, description='密码')
    name = fields.CharField(max_length=255, description='姓名')
    # 一对多
    clas = fields.ForeignKeyField('models.Clas', related_name='students')
    # 多对多
    courses = fields.ManyToManyField('models.Course', related_name='students',description='学生选课表')


class Course(Model):
    id = fields.IntField(pk=True)
    name = fields.CharField(max_length=255, description='课程名')
    teacher = fields.ForeignKeyField('models.Teacher', related_name='courses', description='课程讲师')

6.2、aerich迁移工具

main.py

import uvicorn
from fastapi import FastAPI
from tortoise.contrib.fastapi import register_tortoise
from settings import TORTOISE_ORM


app = FastAPI()

# 该方法会在fastapi启动时触发,内部通过传递进去的app对象,监听服务启动和终止事件
# 当检测到启动事件时,会初始化Tortoise对象,如果generate_schemas为True则还会进行数据库迁移
# 当检测到终止事件时,会关闭连接
register_tortoise(
    app,
    config=TORTOISE_ORM,
    # generate_schemas=True,  # 如果数据库为空,则自动生成对应表单,生产环境不要开
    # add_exception_handlers=True,  # 生产环境不要开,会泄露调试信息
)

if __name__ == '__main__':
    uvicorn.run('main:app', host='127.0.0.1', port=8000, reload=True,
                debug=True, workers=1)

settings.py

TORTOISE_ORM = {
    'connections': {
        'default': {
            # 'engine': 'tortoise.backends.asyncpg',  PostgreSQL
            'engine': 'tortoise.backends.mysql',  # MySQL or Mariadb
            'credentials': {
                'host': '127.0.0.1',
                'port': '3306',
                'user': 'root',
                'password': 'root',
                'database': 'fastapi',
                'minsize': 1,
                'maxsize': 5,
                'charset': 'utf8mb4',
                "echo": True
            }
        },
    },
    'apps': {
        'models': {
            'models': ['models', 'aerich.models'],
            'default_connection': 'default',

        }
    },
    'use_tz': False,
    'timezone': 'Asia/Shanghai'
}

aerich是一种ORM迁移工具,需要结合tortoise异步orm框架使用。安装aerich

pip install aerich

1. 初始化配置,只需要使用一次

aerich init -t settings.TORTOISE_ORM # TORTOISE_ORM配置的位置)

初始化完会在当前目录生成一个文件:pyproject.toml和一个文件夹:migrations

  • pyproject.toml:保存配置文件路径,低版本可能是aerich.ini

  • migrations:存放迁移文件

2. 初始化数据库,一般情况下只用一次

aerich init-db
  1. 此时数据库中就有相应的表格

  2. 如果TORTOISE_ORM配置文件中的models改了名,则执行这条命令时需要增加--app参数,来指定你修改的名字

3. 更新模型并进行迁移

修改model类,重新生成迁移文件,比如添加一个字段

aerich migrate [--name] (标记修改操作) #  aerich migrate --name add_column

迁移文件名的格式为 {version_num}{datetime}{name|update}.json。

注意,此时sql并没有执行,数据库中表中没有addr字段。

4. 重新执行迁移,写入数据库

aerich upgrade

5. 回到上一个版本

aerich downgrade

6. 查看历史迁移记录

aerich history

6.3 选课系统接口开发

api/student.py

from fastapi.exceptions import HTTPException

from models import *

from pydantic import BaseModel
from typing import List, Union
from fastapi import APIRouter

api_student = APIRouter()


@api_student.get("/student")
async def getAllStudent():
    students = await Student.all().values("name", "clas__name")
    # students = await Student.filter(name__icontains='a').values("name", "clas__name")
    # print("students", students)
    # for i in students:
    #     print(i)
    #
    # rain = await Student.get(name='rain')
    # print(rain, type(rain))
    # print(rain.sno)

    return students


class StudentModel(BaseModel):
    name: str
    pwd: str
    sno: int
    clas_id: Union[int, None] = None
    courses: List[int] = []


@api_student.post("/student")
async def addStudent(stu: StudentModel):
    # 添加数据库操作
    # 方式1
    # student = Student(name=stu.name, pwd=stu.pwd, sno=stu.sno, clas_id=stu.clas)
    # await student.save()
    # 方式2
    student = await Student.create(name=stu.name, pwd=stu.pwd, sno=stu.sno, clas_id=stu.clas_id)
    print(student, dir(student))

    # 添加多对多关系记录
    courses = await Course.filter(id__in=stu.courses)
    print("courses", courses)
    await student.courses.add(*courses)
    print("student", student.courses)

    return student


@api_student.put("/student/{student_id}")
async def update_student(student_id: int, student: StudentModel):
    data = student.dict(exclude_unset=True)
    courses = data.pop("courses")
    print(data, courses)
    await Student.filter(id=student_id).update(**data)

    courses = await Course.filter(id__in=student.courses)
    edit_student = await Student.get(id=student_id)
    await edit_student.courses.clear()
    await edit_student.courses.add(*courses)

    return student


@api_student.delete("/student/{student_id}")
async def delete_student(student_id: int):
    deleted_count = await Student.filter(id=student_id).delete()  # 条件删除
    if not deleted_count:
        raise HTTPException(status_code=404, detail=f"Student {student_id} not found")
    return {}

六、中间件与CORS

6.1 中间件

你可以向 FastAPI 应用添加中间件.

"中间件"是一个函数,它在每个请求被特定的路径操作处理之前,以及在每个响应之后工作.

如果你使用了 yield 关键字依赖, 依赖中的退出代码将在执行中间件后执行。

如果有任何后台任务(稍后记录), 它们将在执行中间件后运行。

要创建中间件你可以在函数的顶部使用装饰器 @app.middleware("http").

中间件参数接收如下参数:

  • request

  • 一个函数call_next,它将接收request,作为参数。

    • 这个函数将 request 传递给相应的 路径操作。

    • 然后它将返回由相应的路径操作生成的 response。

  • 然后你可以在返回 response 前进一步修改它。

import uvicorn
from fastapi import FastAPI

from fastapi import Request
from fastapi.responses import Response
import time

app = FastAPI()


@app.middleware("http")
async def m2(request: Request, call_next):
    # 请求代码块
    print("m2 request")
    response = await call_next(request)
    # 响应代码块
    response.headers["author"] = "yuan"
    print("m2 response")
    return response


@app.middleware("http")
async def m1(request: Request, call_next):
    # 请求代码块
    print("m1 request")
    # if request.client.host in ["127.0.0.1", ]:  # 黑名单
    #     return Response(content="visit forbidden")

    # if request.url.path in ["/user"]:
    #     return Response(content="visit forbidden")

    start = time.time()

    response = await call_next(request)
    # 响应代码块
    print("m1 response")
    end = time.time()
    response.headers["ProcessTimer"] = str(end - start)
    return response


@app.get("/user")
def get_user():
    time.sleep(3)
    print("get_user函数执行")
    return {
        "user": "current user"
    }


@app.get("/item/{item_id}")
def get_item(item_id: int):
    time.sleep(2)
    print("get_item函数执行")
    return {
        "item_id": item_id
    }


if __name__ == '__main__':
    uvicorn.run('main:app', host='127.0.0.1', port=8030, reload=True,
                debug=True, workers=1)

6.2 CORS

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
</head>
<body>

<p>click</p>

<script>
  
    $("p").click(function () {
        $.ajax({
            url: "http://127.0.0.1:8080/",
            success: function (res) {
                $("p").html(res.message)
            },
        })
    })

</script>
</body>
</html>
@app.middleware("http")
async def CORSMiddleware(request: Request, call_next):
    response = await call_next(request)
    print(response.headers)
    return response
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()
origins = [
    "http://localhost:63342"
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,  # *:代表所有客户端
    allow_credentials=True,
    allow_methods=["GET"],
    allow_headers=["*"],
)

@app.get("/")
def main():
    return {"message": "Hello World"}


if __name__ == '__main__':
    import uvicorn

    uvicorn.run("main:app", host="127.0.0.1", port=8080, debug=True, reload=True)

  • 20
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我向往自由

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值