写的不全!参考视频
@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服务器根据收到的请求后,向客户端发送响应信息。
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请求协议与响应协议
http协议包含由浏览器发送数据到服务器需要遵循的请求协议与服务器发送数据到浏览器需要遵循的响应协议。用于HTTP协议交互的信息被称为HTTP报文。请求端(客户端)的HTTP报文做请求报文,响应端(服务器端)做响应报文。HTTP报文本身是由多行数据构成的字文本。
一个完整的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.前后端不分离【客户端看到的内容和所有见面效果都是由服务器端提供出来的】 2.前后段分离【把前端的界面效果html,css,js分离到另一个服务端,python服务端只需要返回数据即可】
前端形成一个独立的网站,服务端构成一个独立网站
应用程序编程接口(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 APIRouterapp01 = 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 FastAPIimport uvicornfrom fastapi.staticfiles import StaticFilesfrom apps.app01 import app01from apps.app02 import app02from apps.app03 import app03from apps.app04 import app04from apps.app05 import app05from apps.app06 import app06from apps.app07 import app07app = FastAPI() app.mount("/static" ,StaticFiles(directory="statics" ),name="statics" ) 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 路径参数
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 APIRouterfrom typing import Union ,Optional 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 APIRouterfrom pydantic import BaseModel,Field,validator from datetime import datefrom typing import List ,Optional ,Union app03 = APIRouter() class Address (BaseModel ): city: str street: str class User (BaseModel ): 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from fastapi import APIRouterfrom pydantic import BaseModel,Field,validator from datetime import datefrom typing import List ,Optional ,Union from fastapi import Formapp04 = 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 APIRouterfrom pydantic import BaseModel,Field,validator from datetime import datefrom typing import List ,Optional ,Union import osfrom fastapi import Form,File,UploadFileapp05 = 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 APIRouterfrom fastapi import Requestapp06 = 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产生的文件为静态 静态网站和动态网站 21 (1 )response_model 前面写的这么多路径函数最终return 的都是自定义结构的字典,FastAPI提供了response_model参数,声明return 响应体的模型 FastAPI将树勇response_model进行以下操作 - 将输出数据转换成response_model中声明的数据类型。 - 验证数据结构和类型 - 将输出数据限制为改model定义的 - 添加到OpenAPI中 - 在自动文档系统中使用 你可以在任意的路径操作中使用response_model参数来声明用于响应的模型 案例: - 注册功能 - 输入账号、密码、昵称、邮箱 (2 )response_model_ exclude_unset 要了解jinjia2,那么需要先俩节模版的概念。模版在python的web开发中广泛使用,它能够有效的将业务逻辑和页面逻辑分开,使代码可读性增强、并且更加容易理解和维护。 模版简单来说解释一个其中包含占位变量表示动态的部分的文件,模版文件在经过动态赋值后,返回给用户。 jinjia2是Flask作者开发的一个模版系统,起初是仿django模版的一个模版引擎,为Flask提供模版支持,由于其灵活,快速和安全等优点被广泛使用。 在jinja2中,存在三种语法 1. 变量取值{{}}2. 控制结构{%%}变量可以通过“过滤器”进行修改,过滤器可以理解为是jinjia2里面的内置函数合字符串处理函数。常用的过滤器有“ | 过滤器名称 | 说明 | | ----------- | -------------------------------------------- | | capitialize | 把值的首字母转换成大写,其他字母转换成小写 | | lower | 把值转换成小写形式 | | title | 把值中每个单词的首字母都转换成大写 | | trim | 把值的首尾空格去掉 | | striptags | 渲染之前把值中所有的HTML标签都删掉 | | join | 拼接多个值为字符串 | | round | 默认对数字进行四舍五入,也可以用参数进行控制 | | safe | 渲染时值不转义 | 那么如何使用这些过滤器呢?只需要在变量后面使用管道(1 )分割,多个过滤器可以链式调用,前一个过滤器的输出会作为后一个过滤器的输入 ```python {{'abc' |captialize}} {{'abc' |upper}} {{'hello world' |title}} {{'hello world' |replace('world' ,'yuan' )|upper}} {{18.18 |round |int }}
5.3 jinjia2的控制结构
5.3.1、分支控制
jinjia2中的if语句类似于python的if语句,它也具有单分支,多分支等多种结构,不同的是,条件语句不需要使用冒号结尾,而结束控制语句,需要使用endif关键字