python自动化测试:request模块
python的requests模块
requests是 Python 中最流行的 HTTP 客户端库,以简洁优雅的 API 著称,用于发送 HTTP/HTTPS 请求。以下是其核心使用场景和常用方法详解:
一、核心使用场景
- API 调用
- 与 RESTful API 交互(如获取天气数据、股票行情、社交媒体接口)。
- 示例:调用 GitHub API 获取用户信息。
- 网页内容抓取(Web Scraping)
- 获取网页 HTML 源码,配合解析库(如 BeautifulSoup)提取数据。
- 文件上传/下载
- 上传图片、文档到服务器;下载文件(如 PDF、图片)。
- 自动化测试
- 模拟用户请求,测试 Web 服务的功能和性能。
- 会话管理
- 维持登录状态(Cookies)、处理跨请求参数(如 CSRF Token)。
- 处理认证
- 支持 Basic Auth、OAuth、JWT 等认证机制。
二、常用方法详解
1. 发送 GET 请求(获取数据)
import requests
# 基础用法
response = requests.get("https://api.example.com/data")
# 带查询参数 (自动编码为 ?key1=value1&key2=value2)
params = {"page": 2, "limit": 10}
response = requests.get("https://api.example.com/data", params=params)
# 自定义请求头 (如模拟浏览器)
headers = {"User-Agent": "Mozilla/5.0"}
response = requests.get(url, headers=headers)
- 关键属性:
response.status_code:HTTP 状态码(200、404 等)response.text:响应内容(字符串)response.json():解析 JSON 响应(自动转换字典)response.content:二进制响应内容(如下载图片)
2. 发送 POST 请求(提交数据)
# 表单数据 (application/x-www-form-urlencoded)
data = {"username": "admin", "password": "12345"}
response = requests.post("https://api.example.com/login", data=data)
# JSON 数据 (application/json)
json_data = {"name": "John", "age": 30}
response = requests.post("https://api.example.com/users", json=json_data)
3. 其他 HTTP 方法
requests.put(url, data={}) # 更新资源
requests.delete(url) # 删除资源
requests.head(url) # 获取响应头(无正文)
requests.patch(url, data={}) # 部分更新资源
4. 文件上传
files = {"file": open("photo.jpg", "rb")}
response = requests.post("https://api.example.com/upload", files=files)
5. 会话管理(Session)
with requests.Session() as s:
# 登录一次,后续请求自动携带 Cookies
s.post("https://example.com/login", data={"user": "a", "pass": "b"})
# 访问需要登录的页面
response = s.get("https://example.com/dashboard")
6. 超时与异常处理
try:
# 设置超时(连接+读取时间)
response = requests.get(url, timeout=(3.05, 27))
except requests.exceptions.Timeout:
print("请求超时!")
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
三、高级功能
| 功能 | 代码示例 |
|---|---|
| 代理设置 | proxies = {"http": "http://10.10.1.10:3128"}; requests.get(url, proxies=proxies) |
| SSL 证书验证 | requests.get(url, verify=False)# 忽略证书错误(慎用!) |
| 重定向控制 | requests.get(url, allow_redirects=False) |
| 流式下载大文件 | response = requests.get(url, stream=True); for chunk in response.iter_content(chunk_size=8192): ... |
四、最佳实践
-
总是检查状态码
if response.status_code == 200: print("Success!") elif response.status_code == 404: print("Not Found!") -
使用上下文管理器释放资源
with requests.get(url, stream=True) as r: r.raise_for_status() # 检查错误 -
避免阻塞主线程
在异步框架(如 asyncio)中使用
aiohttp替代。
五、安装
pip install requests
注意:Requests 仅支持 Python 3.6+,对于异步需求可搭配
httpx或aiohttp。
通过灵活组合上述方法,requests能高效处理绝大多数 HTTP 交互场景,是 Python 网络编程的首选工具之一。
为什么测试场景优先使用requests.session
在测试场景(尤其是 Web 应用测试)中,优先使用 request.session(或 requests.Session())而非直接发送请求,主要基于以下核心原因:
一、核心原因:维持会话状态(Session State)
- Cookie 持久化
- 用户登录后,服务器通过
Set-Cookie返回身份凭证(如 Session ID) - 后续请求需自动携带 Cookie 才能保持登录态
Session对象自动存储并发送 Cookie,无需手动处理
- 用户登录后,服务器通过
- 模拟真实用户行为
- 真实用户操作是连续的会话过程(登录 → 浏览 → 下单)
Session确保所有请求在同一个会话上下文中执行
二、测试场景下的具体优势
1. 身份认证自动化
# 使用 Session 实现登录态保持
session = requests.Session()
login_data = {"user": "test", "pass": "123"}
session.post("https://example.com/login", data=login_data) # 登录
# 后续请求自动携带 Cookie
profile = session.get("https://example.com/profile") # 访问个人页
orders = session.get("https://example.com/orders") # 查看订单
2. 跨请求数据共享
-
CSRF Token 处理
某些网站在登录后返回动态 Token,需在后续请求的 Header 中携带:
# 首次请求获取 Token resp = session.get("https://example.com/form") csrf_token = extract_token(resp.text) # 从HTML中提取 # 后续请求自动携带 Token session.headers.update({"X-CSRFToken": csrf_token}) session.post("https://example.com/submit", data={...})
3. 连接复用提升性能
Session底层使用 HTTP 持久连接(Keep-Alive)- 减少 TCP 握手开销,比多次独立请求快 2-3 倍
4. 统一配置管理
# 全局设置 Headers/Proxies/Auth
session = requests.Session()
session.headers.update({
"User-Agent": "MyTestAgent/1.0",
"Accept-Language": "en-US"
})
session.proxies = {"https": "http://proxy.example.com:8080"}
# 所有请求自动继承配置
resp1 = session.get("/api/data")
resp2 = session.post("/api/update", json={...})
三、对比:直接使用 requests.get()的缺陷
# 错误示范:每次请求都是新会话
resp_login = requests.post(login_url, data=...) # 获得 Cookie
resp_profile = requests.get(profile_url) # ❌ 丢失登录 Cookie!
- 每次请求独立:无法维持登录状态
- 手动处理 Cookie:需从响应中提取并设置到后续请求
- 重复配置:每个请求都要单独设置 Headers/Auth
四、典型测试场景案例
场景:测试电商下单流程
def test_checkout_flow():
# 1. 创建会话
s = requests.Session()
# 2. 登录
s.post("/login", data={"user": "buyer", "pwd": "secret"})
# 3. 添加商品到购物车(自动携带登录态)
s.post("/cart/add", json={"product_id": 1001})
# 4. 获取购物车(验证商品已添加)
cart = s.get("/cart").json()
assert len(cart["items"]) > 0
# 5. 提交订单(使用同一会话)
order_resp = s.post("/order/submit", json={"address": "Test St"})
assert order_resp.status_code == 200
五、技术实现原理
sequenceDiagram
participant Test as 测试脚本
participant Session as requests.Session
participant Server as 被测服务器
Test->>Session: 创建 Session 对象
Session->>Server: 发送登录请求 (携带初始 Cookie)
Server-->>Session: 返回 Set-Cookie (SessionID)
Session->>Session: 存储 Cookie 到 CookieJar
Test->>Session: 发送后续请求
Session->>Server: 自动附加 Cookie
Server-->>Session: 返回授权后的响应
六、最佳实践建议
-
始终优先使用 Session
除非单次独立请求(如公开 API 调用)
-
结合上下文管理器
with requests.Session() as s: s.post("/login", ...) s.get("/dashboard") # 退出时自动关闭连接 -
敏感操作隔离
不同测试用例使用独立 Session,避免状态污染
-
清理会话数据
测试结束后调用
session.close()释放资源
📌 关键结论:在测试场景中,
request.session(或requests.Session())本质是模拟真实用户的浏览器会话,通过维护 Cookie、连接和配置,确保测试流程符合实际业务逻辑。这是 Web 功能测试和爬虫开发的核心实践。
跨域
基本理解
好的,我们来详细介绍一下 跨域。这是一个在前端开发和后端开发中都非常核心的概念。
一、什么是跨域?
跨域 是指一个域下的文档或脚本试图去请求另一个域下的资源时,所发起的 HTTP 请求。
这里的“域”是由 协议、域名、端口 三者共同组成的。只要这三者中有任何一个不同,就构成了跨域。
举个例子:
假设你的前端项目运行在 http://localhost:3000,它要请求的后端 API 地址是 http://api.example.com:8080。
我们来分析一下:
- 协议:
httpvshttp-> 相同 - 域名:
localhostvsapi.example.com-> 不同 - 端口:
3000vs8080-> 不同
由于域名和端口都不同,所以当前端发起请求到后端时,就会产生跨域问题。
同源策略(Same-Origin Policy) 是浏览器的一个核心安全机制。它规定:浏览器默认只允许当前页面的脚本访问与其同源的资源。跨域请求正是被这个策略所限制的。
二、为什么会有跨域问题?(同源策略的目的)
同源策略主要是为了防止恶意网站通过 JavaScript 窃取其他网站的敏感数据(比如你的银行网站 Cookie)。
这里的同源就是上面说的相同的域
一个经典的例子:
- 你登录了
your-bank.com,浏览器保存了你的登录状态(Cookie)。 - 此时你又打开了一个恶意网站
evil-site.com。 - 如果没有同源策略,
evil-site.com上的恶意脚本就可以向your-bank.com发起请求(比如转账),并且浏览器会自动带上你在银行的 Cookie,从而冒充你进行操作。 - 同源策略阻止了这种行为,因为
evil-site.com和your-bank.com不同源。
所以,同源策略是必要的,它保护了用户的安全。 但在现代 Web 开发中,我们常常需要安全地实现跨域通信,这就引出了解决方案。
三、常见的跨域解决方案
跨域的解决方案主要分为两类:JSONP、CORS 以及服务器代理等。其中 CORS 是现代 Web 开发中最主流、最推荐的方案。
1. JSONP(JSON with Padding)
- 原理: 利用
<script>标签没有跨域限制的特性。通过动态创建<script>标签,其src指向目标 URL,并传递一个回调函数的名称。服务器收到请求后,将数据包裹在这个回调函数中返回。浏览器拿到响应后,会立即执行这个回调函数,从而实现数据的获取。 - 优点: 兼容性非常好,支持老式浏览器。
- 缺点:
- 只支持 GET 请求。
- 存在安全风险(可能遭受 XSS 攻击)。
- 需要前后端同时配合修改代码。
- 现状: 随着 CORS 的普及,JSONP 已逐渐被淘汰,仅在一些遗留系统中使用。
2. CORS(Cross-Origin Resource Sharing,跨域资源共享)
-
原理: 这是 W3C 标准,也是目前解决跨域问题的主流方案。它通过服务器在响应头中添加特定的字段,来告诉浏览器:“我允许来自某个源的请求访问我的资源”。浏览器会检查这些响应头,如果符合条件,则允许前端 JavaScript 访问响应数据。
-
关键点: CORS 的实现主要在服务器端。
-
简单请求 vs 预检请求:
- 简单请求: 满足特定条件(如 GET、HEAD、POST 方法,且 Content-Type 为
text/plain,multipart/form-data,application/x-www-form-urlencoded等)的请求,不会触发预检。 - 预检请求(Preflight Request): 对于非简单请求(如使用 PUT、DELETE 方法,或
Content-Type: application/json),浏览器会先自动发送一个OPTIONS方法的请求到服务器,询问是否允许实际请求。服务器必须响应允许后,浏览器才会发送真正的请求。
- 简单请求: 满足特定条件(如 GET、HEAD、POST 方法,且 Content-Type 为
-
服务器端设置示例(以 Node.js/Express 为例):
const express = require('express'); const app = express(); // 方式一:允许所有来源的跨域请求(不推荐用于生产环境) app.use((req, res, next) => { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization'); res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE'); next(); }); // 方式二:允许特定来源的跨域请求(推荐) app.use((req, res, next) => { const allowedOrigins = ['http://localhost:3000', 'https://my-frontend-app.com']; const origin = req.headers.origin; if (allowedOrigins.includes(origin)) { res.header('Access-Control-Allow-Origin', origin); } res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization'); res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE'); res.header('Access-Control-Allow-Credentials', 'true'); // 如果需要携带 Cookie next(); });Access-Control-Allow-Origin: 指定允许访问资源的源。*表示任意源,但为了安全,最好指定明确的源。Access-Control-Allow-Credentials: 设置为true时,表示允许前端请求携带 Cookie。此时Access-Control-Allow-Origin不能为*,必须指定明确的源。
3. 服务器代理(Proxy)
-
原理: 在开发环境中,前端开发服务器(如 webpack-dev-server, Vite)可以配置一个代理。当前端请求一个同源的接口时,开发服务器会将这个请求转发到真正的后端服务器上。因为服务器之间的请求没有同源策略限制,所以可以成功获取数据,然后再返回给前端。
-
示例(Vite 配置):
// vite.config.js export default defineConfig({ server: { proxy: { '/api': { // 将以 /api 开头的请求代理到 target target: 'http://api.example.com:8080', changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '') // 可选:重写路径 } } } })前端代码只需请求
/api/user,Vite 开发服务器会将其代理到http://api.example.com:8080/user。 -
优点: 对前端代码透明,无需修改后端代码。是解决开发环境跨域的利器。
-
生产环境: 可以通过 Nginx 等反向代理服务器实现同样的效果。
4. 其他方案
- WebSocket: WebSocket 协议本身不受同源策略限制。
- postMessage: 主要用于窗口间(iframe、弹出窗口)的跨域通信。
四、总结
| 方案 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| JSONP | 利用 <script>标签无跨域限制 |
兼容性好 | 只支持 GET,不安全 | 老旧系统,兼容 IE9 以下 |
| CORS | 服务器设置响应头授权 | 标准、安全、功能强大 | 需后端配合,有复杂请求预检 | 现代 Web 开发首选 |
| 代理 | 开发服务器转发请求 | 前端零修改,配置简单 | 仅限开发环境或需 Nginx 配置 | 开发环境必备,生产环境可用 Nginx |
核心要点:
- 跨域是浏览器行为,服务器之间不存在跨域问题。
- 根本解决方案是 CORS,需要后端开发者正确设置响应头。
- 开发阶段使用代理是解决跨域最方便的方法。
- 理解同源策略是为了保护用户安全,而 CORS 是在此基础上提供的一种受控的例外通道。
同源策略的具体执行方式
您问到了一个非常关键的点!您的直觉很接近,但实际情况比“发现就阻止”要稍微复杂一些。
简单回答:不是的。浏览器并不是简单地“发现就阻止”,而是通过一个两阶段的检查流程来实施同源策略,尤其是在处理像 XMLHttpRequest/fetch 这样的“复杂请求”时。
下面我们来详细拆解这个过程,您就会明白为什么需要 CORS 以及它是如何工作的。
同源策略的两种处理方式
浏览器对同源策略的执行,根据请求的类型和危险程度,分为两种情况:
1. 简单请求:直接发出请求,但在接收响应时进行拦截
如果一个请求满足了所有“简单请求”的条件(例如,方法是 GET/HEAD/POST,且 Content-Type 为 text/plain, application/x-www-form-urlencoded, multipart/form-data等),浏览器会:
- 正常发出请求:浏览器不会阻止请求的发出,它会像发送同源请求一样,将请求发送到服务器。
- 检查响应头:当服务器的响应返回给浏览器时,浏览器会审查响应头。
- 决定是否放行数据:
- 如果响应头中包含
Access-Control-Allow-Origin并且该值匹配当前页面的源(或为通配符*),浏览器就认为服务器“同意”这次跨域访问,于是将响应数据交给前端 JavaScript。 - 如果响应头中没有
Access-Control-Allow-Origin,或者该值与当前源不匹配,浏览器就会拦截响应,并在控制台报错。此时,前端 JavaScript 拿不到任何响应数据,但开发者工具的网络面板里能看到服务器其实已经返回了 200 OK 的数据。
- 如果响应头中包含
2. 非简单请求(预检请求):先“请示”,再“行动”
对于“非简单请求”(例如,使用了 PUT/DELETE 方法,或者 Content-Type: application/json),浏览器认为这可能是一个高风险操作,所以它引入了一个叫做 “预检请求(Preflight Request)” 的安全机制。这个过程清晰地展示了同源策略并非“一刀切”地阻止,而是一个协商过程。
其完整流程如下:
第①步:浏览器自动发起 OPTIONS 预检请求
在发送真正的业务请求之前,浏览器会自动地、悄悄地先向服务器发送一个 OPTIONS方法的请求。
这个 OPTIONS请求就像是去服务器那里“敲门请示”,它里面包含了几个关键的头部信息,用来询问服务器:
Origin: 表明我(浏览器)这次请求的真正来源是哪个域。Access-Control-Request-Method: 告诉服务器,我接下来的真实请求打算用什么 HTTP 方法(比如PUT)。Access-Control-Request-Headers: 告诉服务器,我接下来的真实请求打算携带哪些自定义的头部(比如X-Token)。
第②步:服务器响应预检请求
服务器收到这个 OPTIONS请求后,并不会处理业务逻辑,而是专门根据请求头里的信息来判断是否允许此次跨域。
服务器需要回应一个特殊的响应,包含以下关键头部:
Access-Control-Allow-Origin: 明确告知浏览器,我允许哪个源进行跨域访问。Access-Control-Allow-Methods: 明确告知浏览器,我允许哪些 HTTP 方法(如GET, POST, PUT)。Access-Control-Allow-Headers: 明确告知浏览器,我允许哪些自定义头部。Access-Control-Max-Age: (可选)告知浏览器,这个预检结果可以被缓存多久(比如 86400 秒),在此期间内,对于同样的跨域请求,不需要再次发送预检。
第③步:浏览器判断是否继续发送真实请求
浏览器拿到服务器对 OPTIONS请求的响应后,会检查上面的几个头部字段。
- 如果服务器允许(例如,
Access-Control-Allow-Origin包含了我的源),那么浏览器就会进入下一步。 - 如果服务器拒绝或不回应,浏览器会直接拦截并报错,真实的业务请求永远不会被发出。
第④步:浏览器发送真实的业务请求
预检通过后,浏览器才会按照原计划,发送那个真正的 PUT/DELETE或带有 application/json的 POST请求。
第⑤步:浏览器检查真实请求的响应
最后,浏览器会用和“简单请求”相同的逻辑来处理服务器的响应:检查响应头中的 Access-Control-Allow-Origin等字段,以决定是否将数据交给前端 JavaScript。
总结与类比
为了帮助您更好地理解,我们可以做一个简单的类比:
- 同源策略:就像一个国家的海关政策,原则上不允许外国人随便进出。
- 简单请求:像一个普通游客想入境旅游。他可以直接买机票飞过去(发出请求),但入境时边检官员(浏览器)会检查他的签证(响应头中的 CORS 信息)。没签证就不让进(拦截数据)。
- 非简单请求(预检):像一个商人想带特殊设备入境谈生意。他不能直飞,必须先发电报给外交部(发送 OPTIONS 预检请求),询问“我带A设备、用B方式谈判行不行?”。外交部批准了(服务器响应允许),他才能买机票带着设备过来(发送真实请求)。最后入境时还要再出示一次批文(检查最终响应的 CORS 信息)。
所以,同源策略的核心作用是“控制”,而不是单纯的“阻止”。它通过这种精细化的流程,既保障了安全性,又为合法的跨域通信提供了标准化的途径,而这个途径就是我们所说的 CORS。

浙公网安备 33010602011771号