写的不全!
参考视频

@fastapi框架

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

Starlette:一个用于构建ASGI(异步服务器网关接口)的web框架
Pydantic:一个用于数据验证和序列化的库

1 预备知识点

1.1 http协议

1.1.1 简介

HTTP协议是Hyper Text Transfer Protocol的缩写,它是一个用于在Internet上传输超文本的协议。HTTP是一个属于应用层的面向对象的协议。由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于1990年提出,经过几年的使用与发展,得到不断的完善和拓展。HTTP工作与客户段-服务端架构上。浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。Web服务器根据收到的请求后,向客户端发送响应信息。
alt text

1.1.2 http协议特性

  • 基于TCP/IP协议
    • http协议是基于TCP/IP协议之上的应用层协议
  • 基于请求、响应模式
    • HTTP协议规定规定,请求从客户端发出,最后服务器端响应应该请求并返回,换句话说肯定是从客户端开始建立通信的,服务器端在没有接收到请求之前不会发送响应。
  • 无状态保存
    • HTTP是一种不草村状态,即无状态stateless协议。HTTP协议 自身不对请求和响应之间的同学状态进行保存。也就是说在HTTP这个级别,协议对于发送过的请求或响应都不会做持久化处理
    • 使用HTTP协议,每当有新的请求发送时,就会有对应的新响应产生。协议本身并不保留之前一切的请求或响应报文信息,这是为了更快地处理大量食物,确保协议的可伸缩性,而特意把HTTP协议设计成如此简单。
  • 短连接
    • HTTP1.0默认使用的是短连接,浏览器和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。
    • HTTP1.1默认使用的是长连接,浏览器和服务器之间建立连接,并一直保持连接,直到客户端主动关闭连接。
    • HTTP长连接,指的是复用TCP连接,多个HTTP请求可以复用同一个TCP连接,这就节省了TCP连接建立和断开的消耗

1.1.3 http请求协议与响应协议

alt text

http协议包含由浏览器发送数据到服务器需要遵循的请求协议与服务器发送数据到浏览器需要遵循的响应协议。用于HTTP协议交互的信息被称为HTTP报文。请求端(客户端)的HTTP报文做请求报文,响应端(服务器端)做响应报文。HTTP报文本身是由多行数据构成的字文本。

alt text

一个完整的URL包括:协议、ip、端口、路径、参数

例如:https://www.baidu.com/s?wd=python 其中https是协议,www.baidu.com是ip/域名,端口默认是80,/s是路径,wd=python是参数

请求方式:get与post请求

  • GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditBook?name=test 1&id=1。POST方法是把提交的数据放在请求体中,即POST方法提交的数据放在请求体中。
  • GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制

响应状态码:状态码的职责是当客户端向服务端发送请求时,返回的请求结果。借助状态码,用户可以知道服务器端是正常处理了,还是出现了。状态码如200 ok,以三位数字和原因组成。

1.2 api接口

在开发Web应用中,有两种应用模式:

1.前后端不分离【客户端看到的内容和所有见面效果都是由服务器端提供出来的】
alt text
2.前后段分离【把前端的界面效果html,css,js分离到另一个服务端,python服务端只需要返回数据即可】

前端形成一个独立的网站,服务端构成一个独立网站

alt text

应用程序编程接口(API),就是应用程序对外提供了一个操作数据的入口,这个入口可以是一个函数或类方法,也可以是一个url地址或者一个网络地址。当客户端调用这个入口,应用程序则会执行对应代码操作,给客户端完成对应的功能。

当然,api接口在工作中是比较常见的开发内容,有时候,我们会调用其他人编写的api接口,有时候,我们也需要提供api接口给其他人操作,由此就会带来一个问题,api接口往往都是一个函数、类方法,或者url或其他网络地址,不管是哪一种,当api接口编写过程中,我们都要考虑一个问题是这个接口应该怎么编写?接口怎么写更加容易维护和清晰,者就需要大家在调用或者编写api接口的时候要有一个明确的编写规范!!!

为了在团队内部形成共识,防止个人习惯差异引起的混乱,我们都需要找到一种大家都觉得很好的接口实现规范,而且这种规范能够让后端写的接口,用途一目了然,减少客户端和服务端双方之间的合作成本。

目前市面上大部分公司开发人员使用的接口实现规范只要有restful,RPC

REST全称是Representational State Transfer,中文翻译为表现层状态转化,是RESTful风格的一种实现方式。是一种专门为Web开发而定义的API接口的设计风格,尤其适用于前后端分离的应用模式中。

关键:面向资源开发

这种风格的理念认为后段开发任务就是提供数据的,对外提供的是数据资源的访问接口,所以在定义接口时,客户端访问的URL路径就表示这种药操作的数据资源。

面对于数据资源分别使用POST、GET、PUT、DELETE等HTTP请求方法,分别对应增删改查操作。

2 quick start

简单案例

安装pip install fastapi

ASGI服务器,生产环境可以使用Uvicorn
pip install uvicorn

code

1
2
3
4
5
6
7
8
9
10
11
12
from fastapi import APIRouter

app01 = APIRouter()

# 路由匹配顺序,上面的路由会覆盖下面的路由
@app01.get('/users/{user_id}')
def get_user(user_id: int):
return {'user_id': user_id}

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

3 路径操作

对于我来说没啥实际用处的部分的就直接省了,有需要可以去看视频。

include_router

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from fastapi import FastAPI
import uvicorn
from fastapi.staticfiles import StaticFiles

from apps.app01 import app01
from apps.app02 import app02
from apps.app03 import app03
from apps.app04 import app04
from apps.app05 import app05
from apps.app06 import app06
from apps.app07 import app07

app = FastAPI()

app.mount("/static",StaticFiles(directory="statics"),name="statics") # directory指定静态文件目录

app.include_router(app01,prefix="/app01",tags=["01 路径参数"])
app.include_router(app02,prefix="/app02",tags=["02 查询参数"])
app.include_router(app03,prefix="/app03",tags=["03 请求体数据"])
app.include_router(app04,prefix="/app04",tags=["04 form表单数据"])
app.include_router(app05,prefix="/app05",tags=["05 文件上传"])
app.include_router(app06,prefix="/app06",tags=["06 Request对象"])
app.include_router(app07,prefix="/app07",tags=["07 响应参数"])

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


4 请求与响应

4.1 路径参数

  • 基本用法

    以使用与python格式化字符串相同的语法声明路径“参数”或“变量”

1
2
3
@app.get('/items/{item_id}')
async def read_item(item_id: int):
return {'item_id': item_id}

4.2 查询参数(请求参数)

1
2
3
4
5
6
7
8
9
10
11
12
from fastapi import APIRouter
from typing import Union,Optional # Union[str,None] Optional[str] 两个等效
app02 = APIRouter()


@app02.get('jobs')
async def get_jobs(kd,xl:Union[str,None] = None,gj:Optional[str]=None): # 查询参数 有默认参数即非必填
return {'kd': "kd"}

@app02.get('/users/')
def get_user(user_id: int):
return {'user_id'}

4.3 请求体数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from fastapi import APIRouter
from pydantic import BaseModel,Field,validator # 数据校验
from datetime import date
from typing import List,Optional,Union

app03 = APIRouter()

# 嵌套类型
class Address(BaseModel):
city: str
street: str

class User(BaseModel): # 聚合类型
# name: str = Field(regex="^a") # 正则校验 以a开头
name: str
age: int = Field(default=18,gt=0,lt=100)
birth: Union[date,None] = None
frind: List[int] = []
descreption: Optional[str] = None
addr:Address

@validator('name')
def name_max_alpha(cls,value):

assert value.isalpha(),"name 必须是字母"
return value

class Data(BaseModel):
data: List[User]
@app03.post('/user')
async def user(user: User):
print(user.age)
return user

@app03.post('/data')
async def data(data: User):
return data


4.4 form表单数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from fastapi import APIRouter
from pydantic import BaseModel,Field,validator # 数据校验
from datetime import date
from typing import List,Optional,Union

from fastapi import Form

app04 = APIRouter()

@app04.post('/regin')

async def regin(username: str = Form(), password=Form()):
print(f'username:{username},password:{password}')
return {
"username":username
}


4.5 文件上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from fastapi import APIRouter
from pydantic import BaseModel,Field,validator # 数据校验
from datetime import date
from typing import List,Optional,Union
import os
from fastapi import Form,File,UploadFile

app05 = APIRouter()

@app05.post('/file')
async def get_file(file: bytes = File()): # 文件属于字节流数据
# 适合小文件
return {
"file":len(file)
}

# 多文件
@app05.post('/files')
async def get_files(files: List[bytes] = File()): # 文件属于字节流数据
# 适合小文件
return {
"file":len(files)
}

@app05.post('/uploadFile')
async def upload(file: UploadFile = File()): # 文件属于字节流数据
# 适合大文件
print(file.filename)

path = os.path.join("../images/fastapi/images",file.filename)

with open(path,'wb') as f:
f.write(file.file.read())
return {
"file":file.filename
}

4.6 Request对象

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from fastapi import APIRouter

from fastapi import Request

app06 = APIRouter()

@app06.post('/items')
async def items(request:Request):
print("URL",request.url)
print("客户端ip地址",request.client.host)
print("客户端宿主",request.headers.get("user-agent"))
print("cookies",request.cookies)
return {
"items":request.url,
"client_ip":request.client.host,
"client_host":request.headers.get("user-agent"),
"cookies":request.cookies
}

4.7 请求静态文件

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
```

静态文件和动态文件

- 非web产生的文件为静态

静态网站和动态网站

### 4.8 响应模式相关参数

21

1)response_model

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





FastAPI将树勇response_model进行以下操作

- 将输出数据转换成response_model中声明的数据类型。
- 验证数据结构和类型
- 将输出数据限制为改model定义的
- 添加到OpenAPI中
- 在自动文档系统中使用

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

案例:

- 注册功能

- 输入账号、密码、昵称、邮箱





2)response_model_ exclude_unset



## 5 jinja2模版

要了解jinjia2,那么需要先俩节模版的概念。模版在python的web开发中广泛使用,它能够有效的将业务逻辑和页面逻辑分开,使代码可读性增强、并且更加容易理解和维护。

模版简单来说解释一个其中包含占位变量表示动态的部分的文件,模版文件在经过动态赋值后,返回给用户。

jinjia2是Flask作者开发的一个模版系统,起初是仿django模版的一个模版引擎,为Flask提供模版支持,由于其灵活,快速和安全等优点被广泛使用。

在jinja2中,存在三种语法

1.变量取值{{}}

2.控制结构{%%}

### 5.1 jinjia2变量



### 5.2 jinjia2到过滤器

变量可以通过“过滤器”进行修改,过滤器可以理解为是jinjia2里面的内置函数合字符串处理函数。常用的过滤器有“

| 过滤器名称 | 说明 |
| ----------- | -------------------------------------------- |
| capitialize | 把值的首字母转换成大写,其他字母转换成小写 |
| lower | 把值转换成小写形式 |
| title | 把值中每个单词的首字母都转换成大写 |
| trim | 把值的首尾空格去掉 |
| striptags | 渲染之前把值中所有的HTML标签都删掉 |
| join | 拼接多个值为字符串 |
| round | 默认对数字进行四舍五入,也可以用参数进行控制 |
| safe | 渲染时值不转义 |

那么如何使用这些过滤器呢?只需要在变量后面使用管道(1)分割,多个过滤器可以链式调用,前一个过滤器的输出会作为后一个过滤器的输入

```python
{{'abc'|captialize}} # Abc

{{'abc'|upper}} # ABC

{{'hello world'|title}} # Hello World

{{'hello world'|replace('world','yuan')|upper}} # hello world

{{18.18 |round|int}} # 18

5.3 jinjia2的控制结构

5.3.1、分支控制

jinjia2中的if语句类似于python的if语句,它也具有单分支,多分支等多种结构,不同的是,条件语句不需要使用冒号结尾,而结束控制语句,需要使用endif关键字