在上一篇中,我们搭建了接口自动化基础环境,编写并运行了第一个POST接口脚本,但实际工作中,接口场景远不止单一的POST请求------比如获取用户列表用GET请求、提交表单用POST表单请求、上传文件用特殊的POST请求,还有请求头、请求参数、Cookie等必备要素,这些都是接口自动化的核心基础。
本篇作为系列第2篇,聚焦「接口请求全场景实战」,深入讲解Requests库的核心用法,覆盖GET、POST(JSON/表单/文件上传)两种核心请求方式,以及请求头、请求参数、Cookie、超时设置等关键要素,每个场景都提供完整可复制代码、详细注释和运行验证方法,让你能应对企业中80%的基础接口请求场景,同时规范脚本编写格式,为后续框架整合打下基础。
核心目标:掌握各类接口请求的发送方法,能独立解析接口响应,处理不同类型的请求参数和请求头,规范脚本编写,解决实际工作中的基础接口请求问题。
一、核心基础回顾(衔接上一篇,强化记忆)
在开始实战前,我们先回顾两个核心概念,避免新手混淆:
-
接口请求三要素:url(接口地址)、请求方法(GET/POST等)、请求参数(接口需要的输入数据),这是发送任何接口请求都必须具备的要素;
-
接口响应核心要素:状态码(200成功、400参数错误、404接口不存在、500服务器错误)、响应头、响应体(接口返回的核心数据),我们通过响应要素判断接口请求是否成功、返回数据是否正确。
补充:Requests库的核心逻辑------通过requests.请求方法()发送请求,返回一个Response对象,通过该对象获取响应状态码、响应体等信息,常用的Response对象方法如下(必须掌握):
-
response.status_code:获取接口响应状态码;
-
response.json():将响应体转为JSON格式(最常用,适合返回JSON数据的接口);
-
response.text:获取响应体的字符串格式(适合返回HTML、文本的接口);
-
response.headers:获取接口响应头;
-
response.cookies:获取接口返回的Cookie信息。
二、GET请求实战(企业高频场景,重点掌握)
GET请求是最常用的接口请求方式,主要用于「获取数据」(比如获取用户信息、获取商品列表、获取订单详情),特点是请求参数会拼接在URL后面,可见、长度有限制(不适合传输敏感数据、大量数据)。
实战场景:调用公开测试接口(https://httpbin.org/get),发送GET请求,携带请求参数(username、age),获取接口响应并解析。
1. 两种发送GET请求的方式(均需掌握)
GET请求的参数传递有两种方式:参数直接拼接在URL中、通过params参数单独传递(推荐,更规范、易维护),两种方式均提供完整代码。
方式1:参数直接拼接在URL中
import requests
def test_get_api_with_params_in_url():
"""
GET请求实战1:参数直接拼接在URL中
接口地址:https://httpbin.org/get
请求参数:username=test_get,age=25
"""
# 1. 定义接口地址(参数直接拼接在url后面,用?连接,多个参数用&分隔)
url = "https://httpbin.org/get?username=test_get&age=25"
# 2. 发送GET请求(GET请求无需请求体,直接调用requests.get()即可)
# 可选:添加timeout参数,设置请求超时时间(单位:秒),避免接口长时间无响应导致脚本卡死
response = requests.get(url=url, timeout=10)
# 3. 解析响应信息
print("GET请求(参数拼接URL)响应状态码:", response.status_code)
print("GET请求(参数拼接URL)响应体:", response.json())
# 4. 断言验证(核心:验证请求成功、参数传递正确)
# 断言状态码为200,请求成功
assert response.status_code == 200, f"GET请求失败,预期状态码200,实际{response.status_code}"
# 断言接口返回的参数与我们传递的一致(response.json()["args"]中存储了GET请求的参数)
assert response.json()["args"]["username"] == "test_get", "GET请求参数传递错误,username不匹配"
assert response.json()["args"]["age"] == "25", "GET请求参数传递错误,age不匹配"
# 运行脚本
if __name__ == "__main__":
test_get_api_with_params_in_url()
方式2:通过params参数单独传递(推荐)
当请求参数较多时,直接拼接在URL中会显得杂乱、易出错,通过params参数传递,将参数放在字典中,代码更简洁、易维护,后续修改参数也更方便。
import requests
def test_get_api_with_params():
"""
GET请求实战2:通过params参数单独传递请求参数(推荐)
接口地址:https://httpbin.org/get
请求参数:username=test_get_params,age=30,gender=male
"""
# 1. 定义接口核心信息
url = "https://httpbin.org/get"
# 定义请求参数,存储在字典中,key是参数名,value是参数值
params = {
"username": "test_get_params",
"age": 30,
"gender": "male"
}
# 2. 发送GET请求,通过params参数传递请求参数
# timeout=10:设置超时时间为10秒,若10秒内接口无响应,抛出超时异常
response = requests.get(url=url, params=params, timeout=10)
# 3. 解析响应信息
response_json = response.json() # 将响应体转为JSON格式,便于后续断言
print("GET请求(params参数)响应状态码:", response.status_code)
print("GET请求(params参数)传递的参数:", params)
print("GET请求(params参数)接口返回的参数:", response_json["args"])
# 4. 断言验证(更全面,覆盖状态码、参数传递、响应格式)
assert response.status_code == 200, "GET请求失败"
# 断言接口返回的参数与传递的参数完全一致
assert response_json["args"] == {"username": "test_get_params", "age": "30", "gender": "male"}, "GET请求参数传递错误"
# 断言响应体中包含"origin"字段(验证响应格式正确)
assert "origin" in response_json.keys(), "GET请求响应格式异常,缺少origin字段"
# 运行脚本
if __name__ == "__main__":
test_get_api_with_params()
2. GET请求核心要点(企业实战注意事项)
-
参数传递:优先使用params参数传递,代码更规范、易维护,避免参数拼接在URL中导致的错误;
-
超时设置:必须添加timeout参数(建议5-10秒),避免接口长时间无响应导致脚本卡死,影响后续用例执行;
-
敏感数据:GET请求参数会暴露在URL中,不适合传递密码、Token等敏感数据,这类数据优先使用POST请求传递;
-
断言要点:至少验证状态码和核心参数,确保请求成功、参数传递正确,避免漏测。
三、POST请求实战(多场景覆盖,重中之重)
POST请求是企业中最常用的请求方式之一,主要用于「提交数据」(比如登录、注册、提交订单、上传文件),特点是请求参数不暴露在URL中,隐藏在请求体中,可传输敏感数据、大量数据,支持多种参数格式(JSON、表单、文件等)。
本篇重点覆盖企业中最常用的3种POST请求场景:JSON格式参数、表单格式参数、文件上传,每个场景均提供实战代码和验证方法。
场景1:POST请求(JSON格式参数,最常用)
绝大多数企业接口(如登录、注册、更新用户信息)都采用JSON格式传递POST请求参数,Requests库中通过json参数传递JSON格式参数,无需手动设置请求头(Content-Type会自动设为application/json)。
import requests
def test_post_api_with_json():
"""
POST请求实战1:JSON格式参数(最常用)
接口地址:https://httpbin.org/post
请求参数(JSON格式):username=test_post_json,password=123456,login_type=normal
"""
# 1. 定义接口核心信息
url = "https://httpbin.org/post"
# 定义JSON格式请求参数,存储在字典中
json_data = {
"username": "test_post_json",
"password": "123456",
"login_type": "normal",
"remember_me": True # 布尔类型参数,JSON格式支持
}
# 2. 发送POST请求,通过json参数传递JSON格式参数
response = requests.post(url=url, json=json_data, timeout=10)
# 3. 解析响应信息
response_json = response.json()
print("POST请求(JSON参数)响应状态码:", response.status_code)
print("POST请求(JSON参数)请求头:", response_json["headers"]["Content-Type"]) # 验证请求头格式
print("POST请求(JSON参数)传递的参数:", json_data)
print("POST请求(JSON参数)接口返回的参数:", response_json["json"])
# 4. 断言验证(全面覆盖核心场景)
assert response.status_code == 200, "POST请求(JSON参数)失败"
# 断言请求头格式为JSON(验证参数格式传递正确)
assert response_json["headers"]["Content-Type"] == "application/json", "POST请求参数格式不是JSON"
# 断言接口返回的参数与传递的参数完全一致
assert response_json["json"] == json_data, "POST请求(JSON参数)传递错误"
场景2:POST请求(表单格式参数,常用)
部分接口(如提交表单、简单的提交操作)采用表单格式(application/x-www-form-urlencoded)传递POST请求参数,Requests库中通过data参数传递表单格式参数,无需手动设置请求头(Content-Type会自动设为表单格式)。
import requests
def test_post_api_with_form():
"""
POST请求实战2:表单格式参数(常用)
接口地址:https://httpbin.org/post
请求参数(表单格式):username=test_post_form,password=654321,phone=13800138000
"""
# 1. 定义接口核心信息
url = "https://httpbin.org/post"
# 定义表单格式请求参数,存储在字典中(与JSON参数格式一致,但传递方式不同)
form_data = {
"username": "test_post_form",
"password": "654321",
"phone": "13800138000"
}
# 2. 发送POST请求,通过data参数传递表单格式参数
response = requests.post(url=url, data=form_data, timeout=10)
# 3. 解析响应信息
response_json = response.json()
print("POST请求(表单参数)响应状态码:", response.status_code)
print("POST请求(表单参数)请求头:", response_json["headers"]["Content-Type"])
print("POST请求(表单参数)传递的参数:", form_data)
print("POST请求(表单参数)接口返回的参数:", response_json["form"])
# 4. 断言验证
assert response.status_code == 200, "POST请求(表单参数)失败"
# 断言请求头格式为表单格式
assert response_json["headers"]["Content-Type"] == "application/x-www-form-urlencoded", "POST请求参数格式不是表单"
# 断言接口返回的表单参数与传递的一致
assert response_json["form"] == form_data, "POST请求(表单参数)传递错误"
场景3:POST请求(文件上传,实战必备)
企业中常见文件上传场景(如上传头像、上传合同、上传Excel文件),这类POST请求需要传递文件数据,Requests库中通过files参数传递文件,请求头会自动设置为multipart/form-data格式。
import requests
import os
def test_post_api_with_file_upload():
"""
POST请求实战3:文件上传(实战必备)
接口地址:https://httpbin.org/post
上传文件:在项目根目录创建test_upload文件夹,放入一张图片(命名为test_image.jpg)或文本文件
"""
# 1. 定义接口核心信息
url = "https://httpbin.org/post"
# 2. 准备上传的文件(关键:指定文件路径,确保文件存在)
# 定义文件路径(项目根目录下的test_upload文件夹中的test_image.jpg)
file_path = os.path.join(os.getcwd(), "test_upload", "test_image.jpg")
# 验证文件是否存在,避免文件路径错误导致上传失败
assert os.path.exists(file_path), f"上传文件不存在,请检查路径:{file_path}"
# 3. 定义文件上传参数(files参数格式:字典,key是接口要求的文件字段名,value是元组)
# 元组格式:(文件名, 文件对象, 文件类型)
files = {
"file": (
"test_image.jpg", # 上传后的文件名(可自定义,也可使用原文件名)
open(file_path, "rb"), # 以二进制只读模式打开文件(必须是rb模式)
"image/jpeg" # 文件类型(图片:image/jpeg,文本:text/plain,Excel:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet)
)
}
# 4. 发送POST请求,通过files参数传递文件,可同时传递其他参数(json或data)
# 示例:同时传递文件和JSON参数
json_data = {"upload_user": "test_upload", "upload_type": "image"}
response = requests.post(url=url, files=files, json=json_data, timeout=15) # 上传文件超时时间可设置长一点(10-15秒)
# 5. 关闭文件对象(避免资源泄露)
open(file_path, "rb").close()
# 6. 解析响应信息
response_json = response.json()
print("POST请求(文件上传)响应状态码:", response.status_code)
print("POST请求(文件上传)文件字段名:", list(response_json["files"].keys())[0])
print("POST请求(文件上传)同时传递的JSON参数:", response_json["json"])
# 7. 断言验证
assert response.status_code == 200, "POST请求(文件上传)失败"
# 断言文件上传成功(接口返回的files字段中包含我们传递的文件字段名)
assert "file" in response_json["files"].keys(), "文件上传失败,接口未接收文件"
# 断言同时传递的JSON参数正确
assert response_json["json"] == json_data, "POST请求(文件上传)同时传递的JSON参数错误"
# 运行脚本前,先创建test_upload文件夹并放入文件
if __name__ == "__main__":
# 若test_upload文件夹不存在,自动创建
if not os.path.exists("test_upload"):
os.makedirs("test_upload")
print("已自动创建test_upload文件夹,请放入test_image.jpg文件后重新运行脚本")
else:
test_post_api_with_file_upload()
2. POST请求核心要点(企业实战注意事项)
-
参数格式区分:JSON格式用json参数传递,表单格式用data参数传递,文件上传用files参数传递,不可混淆;
-
请求头设置:大多数情况下,Requests会自动根据参数类型设置请求头(Content-Type),无需手动设置;若接口有特殊要求(如自定义请求头),可手动设置headers参数;
-
文件上传:必须以二进制只读模式(rb)打开文件,上传完成后关闭文件对象,避免资源泄露;超时时间可适当延长(10-15秒),避免文件过大导致上传超时;
-
敏感数据:POST请求参数隐藏在请求体中,适合传递密码、Token等敏感数据,是企业接口的首选请求方式。
四、请求头与Cookie实战(企业接口必备)
在企业接口测试中,很多接口需要携带请求头(Headers)或Cookie才能正常请求------比如需要携带User-Agent模拟浏览器请求、携带Token验证身份、携带Cookie保持登录状态,这部分是接口自动化中不可或缺的内容,必须掌握。
1. 请求头(Headers)实战
请求头用于向服务器传递额外的请求信息,比如参数格式、浏览器信息、身份验证信息(Token)等,常见的请求头字段如下:
-
Content-Type:请求参数格式(application/json、application/x-www-form-urlencoded等);
-
User-Agent:模拟浏览器请求,避免接口拦截(部分接口会拦截非浏览器请求);
-
Authorization:身份验证,通常携带Token(如Bearer Token),用于验证用户身份。
实战场景:携带自定义请求头(User-Agent、Authorization)发送POST请求,模拟企业中需要身份验证的接口场景。
import requests
def test_post_api_with_headers():
"""
请求头实战:携带自定义请求头(User-Agent、Token)发送POST请求
接口地址:https://httpbin.org/post
请求头:User-Agent(模拟浏览器)、Authorization(携带Token)
请求参数:JSON格式
"""
# 1. 定义接口核心信息
url = "https://httpbin.org/post"
# 2. 定义请求头(自定义,模拟企业接口场景)
headers = {
"Content-Type": "application/json", # 手动设置请求头(也可省略,json参数会自动设置)
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Authorization": "Bearer fake_token_1234567890" # 模拟携带Token,企业中Token从登录接口获取
}
# 3. 定义请求参数(JSON格式)
json_data = {
"user_id": 1001,
"action": "query_user_info"
}
# 4. 发送POST请求,通过headers参数传递请求头
response = requests.post(url=url, headers=headers, json=json_data, timeout=10)
# 5. 解析响应信息
response_json = response.json()
print("携带请求头的POST请求响应状态码:", response.status_code)
print("携带的请求头:", headers)
print("接口返回的请求头:", response_json["headers"])
# 6. 断言验证
assert response.status_code == 200, "携带请求头的POST请求失败"
# 断言请求头中的User-Agent、Authorization已成功传递
assert response_json["headers"]["User-Agent"] == headers["User-Agent"], "请求头User-Agent传递失败"
assert response_json["headers"]["Authorization"] == headers["Authorization"], "请求头Token传递失败"
2. Cookie实战
Cookie用于保持会话状态(比如登录后,服务器会返回Cookie,后续请求携带该Cookie即可保持登录状态,无需重复登录),Requests库支持自动保存Cookie,也可手动设置Cookie。
实战场景:模拟登录后保存Cookie,后续请求携带该Cookie访问需要登录的接口。
import requests
def test_api_with_cookie():
"""
Cookie实战:模拟登录保存Cookie,后续请求携带Cookie访问接口
场景:登录接口返回Cookie → 携带Cookie访问用户信息接口
测试接口:登录接口(https://httpbin.org/post)、用户信息接口(https://httpbin.org/cookies)
"""
# 第一步:模拟登录,获取Cookie
login_url = "https://httpbin.org/post"
login_data = {"username": "test_cookie", "password": "123456"}
# 发送登录请求,获取响应对象(包含Cookie信息)
login_response = requests.post(login_url, json=login_data, timeout=10)
print("登录请求响应状态码:", login_response.status_code)
print("登录接口返回的Cookie:", login_response.cookies) # 获取登录返回的Cookie
# 第二步:携带登录返回的Cookie,访问用户信息接口
user_info_url = "https://httpbin.org/cookies"
# 方式1:自动携带Cookie(Requests会自动保存登录请求的Cookie,后续请求同一域名会自动携带)
user_info_response1 = requests.get(user_info_url, timeout=10)
# 方式2:手动携带Cookie(适合跨域名、或需要自定义Cookie的场景)
# 将Cookie转为字典格式,通过cookies参数传递
cookies_dict = dict(login_response.cookies)
user_info_response2 = requests.get(user_info_url, cookies=cookies_dict, timeout=10)
# 解析响应信息
print("="*50)
print("自动携带Cookie的响应:", user_info_response1.json())
print("手动携带Cookie的响应:", user_info_response2.json())
# 断言验证
assert login_response.status_code == 200, "模拟登录失败"
assert user_info_response1.status_code == 200, "自动携带Cookie访问用户信息接口失败"
assert user_info_response2.status_code == 200, "手动携带Cookie访问用户信息接口失败"
# 断言Cookie已成功携带
assert cookies_dict.items() <= dict(user_info_response2.cookies).items(), "手动携带Cookie失败"
if __name__ == "__main__":
test_api_with_cookie()
五、脚本规范编写(为后续框架整合铺垫)
新手编写脚本常出现"代码杂乱、无注释、无规范"的问题,导致后续无法复用、难以维护,结合企业实战规范,我们制定以下脚本编写规则,从现在开始严格遵守:
-
文件命名:测试用例文件以test_开头(PyTest框架要求),比如test_get_api.py、test_post_api.py;
-
函数命名:测试用例函数以test_开头,名称清晰,能体现用例场景,比如test_get_user_list、test_post_login;
-
代码注释:每个函数、关键步骤都要添加注释,说明接口用途、参数含义、断言目的,便于后续自己或他人查看;
-
参数管理:请求参数、URL、请求头等核心信息,单独定义变量,避免硬编码(后续会优化为配置文件管理);
-
断言规范:每个用例至少包含1个断言,验证请求成功,核心场景需验证参数传递、响应格式,断言失败时添加提示信息;
-
异常处理:暂时先添加timeout超时设置,后续会补充完整的异常处理(避免脚本崩溃)。
六、本篇总结
-
掌握了GET请求的两种参数传递方式,理解了GET请求的适用场景和核心要点,能独立发送GET请求、解析响应、编写断言;
-
覆盖了POST请求的3种核心场景(JSON参数、表单参数、文件上传),掌握了不同场景下的参数传递方法,能应对企业中绝大多数POST接口请求;
-
学会了请求头和Cookie的使用方法,能携带自定义请求头、Token、Cookie发送请求,解决企业中需要身份验证、会话保持的接口场景;
-
遵守脚本编写规范,编写的脚本简洁、易维护、可复用,为后续框架整合(数据驱动、日志、异常处理)打下基础。
下一篇我们将讲解「数据驱动实战」,通过Excel管理测试数据,实现一套脚本复用多个测试场景,解决"脚本冗余、维护成本高"的问题,进一步提升接口自动化效率!