找回密码
 会员注册
查看: 28|回复: 0

PythonFastAPI一篇文章教你从零搭建自己的网站后台!(新手向)

[复制链接]

7

主题

0

回帖

22

积分

新手上路

积分
22
发表于 2024-9-4 19:48:41 | 显示全部楼层 |阅读模式
2024/4/2更新常见问题当所有环境配置完成后,通过本地访问服务端网址时显示"无法访问此网页",且requests出现连接超时报错;解决办法:登录云服务提供商的控制台,让防火墙放行80,443和8000的出入端口即可。教程说明本教程利用Python异步编程方法,基于FastAPI和uvicorn库来快速搭建并运行网站后台。由于教程偏向于入门,所以我将介绍网站完整建立过程,并对每个可能的疑惑点进行详细解释;如果你已经有自己的服务器,并且掌握SSH和FTP的连接方法,可以直接跳转至第三步。文章预览:2024/4/2更新常见问题教程说明一、准备工作1.申请云服务器2.申请自己的域名二、配置Xshell和Xftp三、服务器环境配置1.创建Python虚拟环境(可选)2.fastapi和uvicorn的安装三、开始编写网站后台四、为服务器配置Nginx代理五、网站连通性测试后记——为server.py添加中间件完整代码一、准备工作一个有公网IP的服务器一个域名(可选)SSH终端:Xshell文件传输:Xftp1.申请云服务器根据业务需求的不同,当然也可以选择租用国外vps,比如:亚马逊:AWS云服务微软:云计算Azure​可能要绑定visa银行卡且收费较高,不过有免费试用额度,访问外网资源速度很快;当然也可选择国内云服务器,比如:腾讯云:弹性云服务器-腾讯云阿里云:云服务器ECS-阿里云​注意:国内服务器和域名都需要进行备案由于作者刚好有阿里云的学生优惠,在申请页面按照官方的引导进行身份认证,于是拿到了一个月免费的服务器;请注意:服务器的系统镜像请选择发行版Linux,比如Ubuntu、CentOS、Debian等,本教程服务器是阿里云的系统(应该是从CentOS魔改来的)2.申请自己的域名由于阿里云学生申请域名首年一块钱,秉持白嫖到底的态度我也申请了一个,暂且称为:mydomain.top​在下单界面需要创建你的信息模版,认证身份并进行备案,按照官方流程即可。3.域名解析当你创建好域名后,前往你的域名控制台在域名列表中,你会看到刚刚申请好的域名,此时点击“解析”—>“新手引导”:继续填写域名解析设置:您的业务需求:这里是根据服务器公网IP来确定的,一般都是xxx.xxx.xxx.xxx格式,即IPv4地址;这里我们选择"解析到IPv4地址"就好;请选择网站域名:如果选择设置@主机记录,则通过http://mydomain.top就能访问我们的网站;如果选择设置WWW主机记录,则通过http://www.mydomain.top才能访问网站;注:设置成WWW的好处是便于我们后续添加子域名,比如api.mydomain.top;这里我们选择WWW记录请输入网站IP:填入之前创建的服务器实例的公网IP就好了解析设置成功后,我们可以在cmd中ping一下我们的域名:pingwww.mydomain.top1如果像图中一样能够Ping得通,就代表我们配置成功了!二、配置Xshell和Xftp[Xshell和Xftp](家庭/学校免费-NetSarangWebsite(xshell.com))这两个软件功能强大、简单易用,且都有家庭和学生免费许可证,比较适合本教程的使用。Xshell功能:通过SSH连接我们服务器的终端,并执行相关命令这里的“主机”填入服务器公网IP;点击“连接”后,会提示你输入用户名和密码,这里根据你服务器的系统账号(一般是root)和密码,对应输入即可;出现SSH密钥确认界面时点击保存。Xftp功能:用于本地与远程服务器之间的文件传输,可以直接复制粘贴文件(这里填写的信息也与Xshell中一致)三、服务器环境配置到这里为止,我们已经成功申请了云服务器和域名,配置好了Xshell与Xftp,那么接下来开始配置我们的服务器环境。查看系统python版本:python--version1本教程使用的Python版本为3.9,建议Python版本为3.7+1.创建Python虚拟环境(可选)教程所使用的FastAPI模块使用了很多Python3.7+的特性,而由于笔者的服务器自带Python3.6版本太低,直接重装可能影响其他系统程序正常工作,故准备建立一个miniconda的虚拟环境。前往miniconda主页查看命令行安装方式:接下来按照官方指引,在Xshell中依此执行下面命令:#在root/下新建"miniconda3"目录mkdir-p~/miniconda3#获取最新miniconda安装包wgethttps://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh-O~/miniconda3/miniconda.sh#执行安装bash~/miniconda3/miniconda.sh-b-u-p~/miniconda3#删除安装包rm-rf~/miniconda3/miniconda.sh12345678910等待终端完成miniconda的安装后,执行下面命令初始化conda:~/miniconda3/bin/condainitbash1接下来创建虚拟环境并命名为myenv,同时安装Python3.9:condacreate--namemyenvpython=3.91等待环境创建完毕,我们启动这个虚拟环境:condaactivatemyenv1此时我们的用户名前缀变成了"(myenv)",这就代表虚拟环境启动成功了!这个环境是独立于系统的Python环境的,我们可以在这个环境下安装所需模块。2.fastapi和uvicorn的安装#用conda安装condainstallfastapicondainstalluvicorn#或者pip安装pipinstallfastapipipinstalluvicorn123456三、开始编写网站后台我们在系统根目录/新建一个mysite目录,用于存放我们的网站文件:mkdir/mysite1在你自己的电脑里,新建一个文件"server.py",这将作为网站的后台,之后会放在服务器的/mysite目录下;使用代码编辑器打开"server.py"并导入我们需要用到的库:#encoding=utf-8importjsonimportasyncioimportuvicornfromfastapiimportFastAPI,Requestfromfastapi.responsesimportJSONResponseapp=FastAPI() 1234567提示:ASGI:是一种异步Web服务器和应用程序之间通信的标准接口,fastapi和uvicorn都是基于此标准的模块;app:我们用fastapi实际上是构建了一个ASGI应用程序,并将其部署在uvicorn上运行;​注:考虑到实际开发中网站需要能处理并发的请求,故我们将采用异步的方式编写后台程序。编写处理”GET“请求的函数#处理GET请求@app.get("/")asyncdefread_root():#读取本目录下的"data.json"文件,将内容返回给客户端withopen("./data.json","r",encoding="utf-8")asf:data=json.load(f)returndata1234567提示app.get("/"):是一个修饰器,用于捕获对server.py所在路径的GET请求;换言之,read_root()这个函数就与根目录/mysite绑定在一起了,外部访问网址www.mydomain.top/就等同访问/mysite目录。在这里我们简单实现了一个读取数据并返回给客户端的方法。编写处理“POST”请求的函数这里简单实现了一个json文件上传功能。#处理POST请求@app.post("/")asyncdefsave_data(data:dict):#将客户端发送的内容存储到本目录下,并向客户端发送一条消息withopen("./data.json","w",encoding="utf-8")asf:json.dump(data,f)return{"message":"Datareceivedandsavedsuccessfully"}1234567​注:Fastapi支持的请求方法不只GET和POST,还有PUT,DELETE等,实现原理与上述相似;最后添加程序入口,并设置监听服务器本地的8000端口:if__name__=="__main__":uvicorn.run(app,host="0.0.0.0",port=8000)12到这一步,我们的网站后台就写好了,只需用Xftp将server.py上传至服务器的/mysite目录下即可:四、为服务器配置Nginx代理我们知道:http协议走80端口,而https走443端口,但我们的网站后台只监听8000端口;为了将其他端口的请求转发到8000端口上,我们还需要配置Nginx进行反向代理。安装nginx#Ubuntusudoaptupdatesudoaptinstallnginx#CentOSsudoyumupdatesudoyuminstallnginx#验证是否安装成功nginx-v123456789使用文本编辑器如vim,打开/etc/nginx/nginx.conf:sudovim/etc/nginx/nginx.conf1找到文件内的server块,并添加location/字段,完成后如下:server{listen80;listen[::]:80;server_name_;root/usr/share/nginx/html;#Loadconfigurationfilesforthedefaultserverblock.include/etc/nginx/default.d/*.conf;error_page404/404.html;location=/40x.html{}error_page500502503504/50x.html;location=/50x.html{}location/{proxy_passhttp://localhost:8000;proxy_set_headerHost$host;proxy_set_headerX-Real-IP$remote_addr;proxy_set_headerX-Forwarded-For$proxy_add_x_forwarded_for;}}123456789101112131415161718192021222324proxy_pass选项用于转发请求至本地的8000端口,要与我们在server.py中填写的端口一致;注意:点击键盘的"Insert键才能开始编辑文件;完成后点"ESC"键退出编辑模式,然后按":“键输入"wq”,回车后保存并退出文件。回到终端界面,我们来启动nginx:#测试Nginx配置是否有误sudonginx-t#启动nginx服务sudosystemctlstartnginx1234最关键的一步——在终端使用uvicorn启动我们的网站后台,设置监听8000端口:#切换到/mysite路径下cd/mysite#启动网站后台uvicornserver:app--host0.0.0.0--port80001234这里的`server:app`其实就是代指我们在`server.py`内定义的`app`程序。1当出现下图时就代表网站后台成功启动了!五、网站连通性测试我们在自己电脑新建一个"client.py",导入requests库进行测试:#encoding=utf-8importrequestsdata={"message":"success"}url="http://www.mydomain.top"#向网站发送一个POST请求r=requests.post(url,data)print(r.json())#输出:{"message":"Datareceivedandsavedsuccessfully"}#向网站发送一个GET请求r=requests.get(url)print(r.json())#输出:{"message":"success"}123456789101112131415在浏览器地址栏填入"http://www.mydomain.top",检查是否能打开;注意:如果在国内服务器上搭建了网站,还需要进行ICP备案,否则会限制网站的访问。在服务器端会记录到我们刚刚请求的消息,若出现200OK字样就代表客户端访问成功了!!后记——为server.py添加中间件其实到这里,我们的所有工作都差不多完成了。不过我突然想到,要是在某段时间内出现大量异常请求如何处理?为了保证网站正常运行,我决定为server.py添加新功能——增加一个预处理请求的中间件,对IP在一段时间内的访问次数进行限制。思路:用异步方法实现一个非阻塞计时器,并在达到阈值时对已保存的IP字典进行清除,代码如下:app=FastAPI()#记录IP访问次数的字典ip_access_count={}#异步任务,用于定期重置IP访问次数asyncdefreset_ip_access_count():whileTrue:awaitasyncio.sleep(3600)#设置每小时清除一次ip_access_count.clear()#启动重置IP访问次数的异步任务,添加一个协程asyncio.create_task(reset_ip_access_count())#处理IP限制中间件@app.middleware("http")asyncdefip_limit_middleware(request:Request,call_next):client_ip=request.client.host#获取请求IP#在IP字典中将该IP访问次数+1ip_access_count[client_ip]=ip_access_count.get(client_ip,0)+1ifip_access_count[client_ip]>100:#当该IP请求次数大于设定阈值时返回403returnJSONResponse(status_code=403,content={"msg":"AccessdeniedforthisIP"})response=awaitcall_next(request)#将请求交给后面处理(这是Fastapi内置方法)returnresponse12345678910111213141516171819202122可以看到我们的拦截是有效的!完整代码importjsonimportasyncioimportuvicornfromfastapiimportFastAPI,Requestfromfastapi.responsesimportJSONResponseapp=FastAPI()#记录IP访问次数的字典ip_access_count={}#异步任务,用于定期重置IP访问次数asyncdefreset_ip_access_count():whileTrue:awaitasyncio.sleep(10)ip_access_count.clear()#启动重置IP访问次数的异步任务asyncio.create_task(reset_ip_access_count())#处理IP限制中间件@app.middleware("http")asyncdefip_limit_middleware(request:Request,call_next):client_ip=request.client.host#获取请求IP#在IP字典中将该IP访问次数+1ip_access_count[client_ip]=ip_access_count.get(client_ip,0)+1ifip_access_count[client_ip]>100:#当该IP请求次数大于设定阈值时返回403returnJSONResponse(status_code=403,content={"msg":"AccessdeniedforthisIP"})response=awaitcall_next(request)#将请求交给后面处理(这是Fastapi内置方法)returnresponse#处理GET请求@app.get("/")asyncdefread_root():withopen("./data.json","r",encoding="utf-8")asf:data=json.load(f)returndata#处理POST请求@app.post("/")asyncdefsave_data(data:dict):withopen("./data.json","w",encoding="utf-8")asf:json.dump(data,f)return{"message":"Datareceivedandsavedsuccessfully"}if__name__=="__main__":uvicorn.run(app,host="0.0.0.0",port=8000)123456789101112131415161718192021222324252627282930313233343536373839404142434445464748阅读至此,若有不解或有错之处,欢迎大家留言喔!(点个收藏关注,不忘迷路~)
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2025-1-3 01:03 , Processed in 0.469313 second(s), 26 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表