fastapi 实现转让接口并限制用户每日访问次数
#!/usr/bin/env python# -*- coding:utf-8 -*-"""@Time: 2022/5/16 16:19@Author: SPZ@File: app@Project: OcrOnlineService@Software: PyCharm"""import jsonimport osfrom io import BytesIOfrom fastapi import F
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
@Time: 2022/5/16 16:19
@Author: SPZ
@File: app
@Project: OcrOnlineService
@Software: PyCharm
"""
import json
import os
from io import BytesIO
from fastapi import FastAPI, UploadFile, File, Form
from fastapi.responses import StreamingResponse, JSONResponse
from fastapi.middleware.cors import CORSMiddleware
import hydra
from config.config_model import config
import aiohttp
from starlette.requests import Request
from enum import Enum
import datetime
import time
from datetime import datetime as dt
count = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0] # 初始访问次数
ip_list = []
d = {}
app = FastAPI()
allowed_origins = ['*']
app.add_middleware(
CORSMiddleware,
allow_origins=allowed_origins,
allow_credentials=True,
allow_methods=['*'],
allow_headers=['*'],
expose_headers=['*']
)
class ResponseType(Enum):
image = 'image'
json = 'json'
@app.post('/OcrTest') # 本地接口
async def ocr_test(request: Request, file: UploadFile = File(...), authorization_code: str = Form(...),
response_type: ResponseType = Form(ResponseType.image)):
if authorization_code != config['authorization_code']:
return JSONResponse({'message': '授权码错误'}, status_code=401)
global count
request_date = dt.today().date()
print(request_date)
now = dt.now()
print(now)
print(config.last_request_date)
if request_date != config.last_request_date: #当最后一次请求的日期与当日日期不同,则重置参数
for idx in range(len(count)):
count[idx] = 0
config.set_date(request_date)
limit_time = config['time_limit']
client_host_ip = request.client.host
flag = 0
pos = 0
for i in ip_list:
if i == client_host_ip: # 找到相等就退出
flag = 1
print("ip出现在列表中的位置:", pos)
break
else:
pos += 1
if flag == 0: # 第一次出现的ip
ip_list.append(client_host_ip)
pos = len(ip_list) - 1
d[client_host_ip] = count[pos]
else: # 之前出现过的ip
d[client_host_ip] = count[pos]
if d[client_host_ip] < limit_time:
data = await file.read() # 先读取本地上传到本地接口的数据
data1 = await interface(data, config, response_type) # 通过本地端口将数据读取到远端端口从而进行相关ocr函数处理
count[pos] += 1
print("今日已试验{}次".format(count[pos]))
daily_charges = limit_time - count[pos]
header = {'daily_charges': str(daily_charges)} #headers改变了
if response_type == ResponseType.image:
return StreamingResponse(BytesIO(data1), media_type='image/png', headers=header)
else:
return JSONResponse(data1, headers=header)
elif d[client_host_ip] >= limit_time:
daily_charges = limit_time - count[pos]
header = {'daily_charges': str(daily_charges)}
print("今日已试验{}次".format(count[pos]))
return JSONResponse({'message': "已达到今日试验次数上限!请明日再使用!"}, status_code=503, headers=header)
# 上传文件
async def interface(file_data: bytes, config, response_type):
url = config.ocr_url
print("url:", url)
multipart_writer = aiohttp.MultipartWriter('mixed')
# add parameters
# 普通参数
data = {'display': response_type.value}
for k, v in data.items():
multipart_writer.append(v).set_content_disposition('form-data', name=k)
# 添加上传文件的参数
# add files data
files = {'files': BytesIO(file_data)}
for k, v in files.items():
# print('k,v:',k,v)
multipart_writer.append(BytesIO(file_data), {'Content-Type': 'image/png'}).set_content_disposition(
'form-data',
name=k,
filename='0.png'
)
# 请求远端端口并读取数据
async with aiohttp.request('POST', url=url, data=multipart_writer, headers={
'Content-Type': 'multipart/form-data; boundary=' + multipart_writer.boundary}) as r:
print(r.status) # 之前访问为422,是因为,添加上传文件的参数名不正确
if response_type == ResponseType.image:
result = await r.content.read()
else:
result = await r.json()
return result
1.总结思路:主要实现的功能就是将自己这台电脑作为访问接口,用户通过访问我这个主机的接口来实现另一端实际接口的访问,即我这个主机接口起到的是中转的作用。其次,第二个功能就是,由于要实现服务器资源的充分利用,不能让用户恶意访问,所以要限制用户每日访问的次数。
这个接口的作用:实现上传一张png图片后,用ocr算法进行处理,返回ocr处理后的图/json信息。
2.其中重要的实现点就是要理解,怎么实现转让接口的,怎么使访问这个接口而实现到另一个接口的功能的?
使用协程等待,用户上传的文件 data = await 函数(xxxx,xxxxx,xx)
config.cor_url即是真正需要访问的接口url
这样就实现了中转!!!这点为思路最重要的点!(因为这个url才是真正上传和处理的接口位置,并且会进行请求远端的端口,返回读取到的数据)
3.怎么实现的对应接口中的参数呢?
其实并没有真正的实现点击上传文件,在对应的远端就执行了上传功能,而是在等着中转接口所有的操作都做完了,点击execute才真正执行到远端。所以不要在这一点上混淆了!并没有实现功能点击一 一对应,而是在最后点击execute以后,才执行远端接口的。
4.怎么实现设置fastapi界面当中的参数的呢?
在装饰函数定义参数当中实现的!
5.远端如何实现上传文件呢?
1.添加普通参数的方法:
2.添加文件参数的方法(最初不知道添加这两种参数是有区别的,就直接将文件参数当作普通参数添加的,发现一直都没有返回图片字节流)
更多推荐
所有评论(0)