背景
最近把AIGC调用的接口部署起来后,在调用过程遇到了点问题,比如图生图的时候没用办法直接传送图片信息,必须进行转码,且图片的大小可能也存在限制。因此,打算系统性的梳理一下遇到的问题和踩过的坑。
FastAPI接口参数定义
我用的接口是用Ray serve进行部署的,Ray是一个分布式的计算框架,包含数据、模型、训练、微调和部署整套流程的服务,这里可以简单理解为该模块是在Fast Api的基础上做了些封装和完善。我定义的接口是一个post的接口,部署起来后,返回的状态码一直显示错误,一直没发现存在什么问题,后面经过多方搜寻,发现错误的原因是传递的参数中存在无法识别的参数。
经过查询后,原来是因为post接口的参数不能随意起,必须以json的格式传送
@app.get("/get")
async def get(a: int, b:int):
'''
一个带有参数的get请求,分别有2个int类型的参数
'''
result = {'a': a, 'b': b}
return result
from pydantic import BaseModel
class User(BaseModel):
a: int
b: int
@app.post("/post")
async def post(request_data: User):
'''
必须传json的post接口, request_data: json字段(User类)
'''
a = request_data.a
b = request_data.b
result = {'a': a, 'b': b}
return result
错误的原因是我把post的参数直接像get一样在接口中声明了,所以就会出错。一般的做法是自己根据需求定义一个参数类,继承BaseModel基类,这个参数类其实就可以当成是一个json来处理了。
UTF-8编码、base64编码、字符与字节的区别和联系
字符是用来显示的,字节是用来存储的。 UTF-8编码是常见的字符编码方式,其他的还有GBK编码等。而base64只能用于字节的编码。对于一个字节还要进行base64的编码,简单来说可能作用就是把所有不统一的字节再经过一轮转换,变成大家都能识别的更小的字节了,就是一个英文字符,如a
,B
这种,每个字符都是一个字节(Bytes),8个Bits,因此英文编码成字节是不存在问题的,如b'ABC'
共有24个比特位,每8个比特位能定位出原字母。但是对于中文字符,每个中文字符需要3个字节才能完整编码(以常用的UTF-8编码方式),如果b'中文'
共有48比特位,中文字符数量又多,因此就会存在编码错误的情况。
base64.b64encode()
图片数据转字节流、字节流转base64编码,与反转
import io
from PIL import Image
import base64
byte_stream = io.BytesIO()
Image.open()
# 1)从路径打开图片,并转换为base64编码后的字符
with open('my_path.png', 'rb')as f:
img_base64_str = str(base64.b64encode(f.read()),"utf-8") # 加一层str和utf-8方便post请求传输json
# 2) Image对象打开图片,并转换为字节流
# 创建一个字节流管道
img_bytes = io.BytesIO()
# 将图片数据存入字节流管道, format可以按照具体文件的格式填写
image.save(img_bytes, format="JPEG") # image是一张可以直接显示的图片
# 从字节流管道中获取二进制
image_bytes = img_bytes.getvalue()
# 3)字节流写入图片路径
with open('my_path.png', 'wb')as f:
f.write(image_bytes )
# 4)将base64编码后的字符转图片
res_image = Image.open(io.BytesIO(base64.b64decode(img_base64_str))) #可直接显示出来
python客户端的http请求
以python-requests模块为例
请求类型
requests请求 | 功能 |
---|---|
requests.get( ) | 从服务器获取数据 |
requests.post( ) | 向服务器提交数据 |
requests.put( ) | 从客户端向服务器传送的数据取代指定的文档的内容 |
requests.delete( ) | 请求服务器删除指定页面 |
requests.head( ) | 请求页面头部信息 |
requests.options( ) | 获取服务器支持的HTTP请求方法 |
requests.patch( ) | 向HTML提交局部修改请求,对应于HTTP的PATCH |
requests.connect( ) | 把请求连接转换到透明的TCP/IP通道 |
requests.trace( ) | 回环测试请求,查看请求是否被修改 |
requests.session( ).get( ) | 构造会话对象 |
get和post是最常用的,一般从字面上理解的话get是获取数据、而post是发送数据,但是实际情况可能会稍微复杂一些:可以用get来发送请求也可以用post来获取数据。在开发中对于获取一般常用get请求,而对于数据的增添、删除、修改,一般都使用post请求进行操作。还有一点,它们两者之间的参数传递也是不同的。get请求是将参数拼接到 url上进行参数传递的,而 post 是将参数写入到请求正文中传递的。
# get请求一般用于数据的查询,请求参数拼接到url路径中,如浏览器中地址栏的url一般都是get请求
# 下面例子get的接口名称为`search`, 接受一个参数`q`
www.douban.com/search?q=电影
get请求会被浏览器主动缓存,如果下次传输的数据相同,那么浏览器就会返回缓存中的内容,以求更快的展示所需要的数据。
相对应的,post请求的数据不会出现在浏览器的地址栏中,因此post 请求不会被缓存,也就不会保留在浏览器历史记录中。而post请求的数据是通过request对象中的data属性来传参,用来存放请求体数据,这里的data是一个字典,里面要有匹配键值对。
请求参数
get的请求参数
常用方式:
response=response.get(url,params,**kwargs)
参数说明:
·url:拟获取页面的url链接
·params:用get方式传进去的参数
·***kwargs:控制参数(非必填)
例子:
1. 参数写在url里面
import requests
response = request.get("http://httpbin.org/get?name=gemey&age=22")
print(response.text)
2. 参数不在url里,独立写在params中
d={
'name':'tom',
'age':'20'
}
response = requests.get('http://httpbin.org/get', params=d)
print(response.text)
post的请求参数
常用方式:
response=response.post(url,data, json, **kwargs)
参数说明:
·url:以post方式请求的地址
·data: 填加到请求体中的数据
·json:Json格式的数据
·**kwargs:控制参数
例子:
requests.post('https://api.github.com/some/endpoint', data=json.dumps({'some': 'data'}))
data参数和params参数的区别: params是添加到url的请求字符串中的,用于get请求。 data是添加到请求体中的, 用于post请求。
data参数和json参数的区别:主要在于查看请求体时候显示的内容不同。用data参数提交数据时,request.body的内容则为a=1&b=2的这种形式,用json参数提交数据时,request.body的内容则为’{“a”: 1, “b”: 2}'的这种形式。
请求响应
response属性 | 功能 |
---|---|
response.text | 获取文本内容 |
response.content | 获取二进制数据 |
response.status_code | 获取状态码 |
response.headers | 获取响应头 |
response.cookies | 获取cookies信息 |
response.cookies.get_dict | 以字典形式获取cookies信息 |
response.cookies.items | 以列表形式获取cookies信息 |
response.url | 获取请求的URL |
response.historty | 获取跳转前的URL |
response.json | 获取json数据 |
常用的就前3个,text返回文本string,content返回文本bytes,status_code返回状态码,状态码分类和含义如下:
状态码 | 分类 | 含义 |
---|---|---|
1** | 信息 | 服务器收到请求,需要请求者继续执行操作 |
2** | 成功 | 请求被成功接收并处理 |
3** | 重定向 | 需要进一步的操作以完成请求 |
4** | 客户端错误 | 请求包含语法错误或无法完成请求 |
5** | 服务器错误 | 服务器在处理请求的过程中发送错误 |
一般http请求没出错的话则返回200,其余都是过程中存在错误导致请求失败。
命令行的http请求
get请求参数:
- 在url中传递参数:可以在url后面使用?连接参数名和参数值,多个参数之间使用&分隔。
- 使用 -d 或 --data 参数:可以使用 -d 参数后面跟随的字符串来传递url编码的参数。
curl http://127.0.0.1:8080/login?admin=admin&passwd=12345678
curl https://www.douban.com/search?q='战争'
curl https://www.douban.com/search -d '{"q":"战争"}'
post请求参数:
- 使用 -d 或 --data 参数:可以使用 -d 参数后面跟随的字符串来传递url编码的参数。
- 使用 -F 参数:可以使用 -F 参数后面跟随的字符串来传递表单参数。
curl -H "Content-Type:application/json" -X POST -d '{"user": "admin", "passwd":"12345678"}' http://127.0.0.1:8000/login
curl常用参数说明
- -H 请求头
- -X 请求方法
- -d 请求参数
- -o 输出文件
请求头部信息是在HTTP请求中包含的元数据,用于提供有关请求的额外信息。这些头部信息提供了关于请求的详细说明,帮助服务器了解请求的性质、期望和所需的处理方式。
以下是一些常见的请求头部信息及其作用:
Content-Type:指定请求体的媒体类型。例如,Content-Type: application/json 表示请求体是 JSON 格式的数据。
Accept:指定客户端可以接受的响应内容类型。服务器可以根据此头部信息来确定要发送给客户端的响应类型。
Authorization:用于在请求中提供身份验证凭据,通常用于访问需要身份验证的资源。常见的方式包括使用 Basic 认证或 Bearer Token。
User-Agent:标识发起请求的客户端应用程序或浏览器的名称和版本号。服务器可以根据此头部信息来处理不同类型的客户端请求。
Referer:指示当前请求是从哪个 URL 发起的。服务器可以根据此头部信息来跟踪请求的来源。
Cookie:用于在请求中发送保存在客户端的 Cookie 数据。服务器可以根据此头部信息来获取客户端的会话信息。
通过设置适当的请求头部信息,你可以控制请求的行为和服务器的处理方式。这些头部信息在与服务器通信时起到了重要的作用,帮助服务器理解和正确处理请求。