更好用的 aiohttp 客户端,支持同步和异步使用。 性能碾压 httpx 和 requests 400%
Project description
💡 为什么选择 nb_aiohttp?
在 Python HTTP 客户端的世界里,我们常常面临一个艰难的选择:
- 选择 requests?简单易用,但性能受限于同步阻塞
- 选择 httpx?同步异步通吃,但性能平平
- 选择 aiohttp?性能卓越,但 API 复杂,不能全局实例化
nb_aiohttp 横空出世,打破这个困局!
我们在 aiohttp 的强大性能基础上,重新设计了更友好的 API,让你既能享受极致性能,又能拥有极简体验。
🚀 核心特性
🏆 性能王者
- 异步性能: 比
httpx快 5倍,完全释放aiohttp的性能潜力 - 同步性能: 比
requests快 4倍,同步代码也能享受异步性能 - 海量并发: 内置连接池管理,轻松应对数万级并发请求
🎯 极简设计
# 一行实例化,全局可用
http = NbAioHttpClient()
# 一行请求,优雅简洁
resp = await http.get('https://api.github.com')
🧩 懒加载机制
彻底解决 aiohttp.ClientSession 无法在模块级别实例化的痛点:
# ✅ nb_aiohttp - 随处实例化
from nb_aiohttp import NbAioHttpClient
http = NbAioHttpClient() # 在全局作用域直接创建
# ❌ aiohttp - 必须在 async 函数内
import aiohttp
async def func():
async with aiohttp.ClientSession() as session: # 每次都要重新创建
...
🔄 同步/异步双支持
一套代码,两种模式,适配各种应用场景:
- NbAioHttpClient: 异步高性能,适合高并发服务
- NbSyncHttpClient: 同步简单调用,适合传统应用、脚本
💪 企业级特性
- ✅ 自动重试: 智能重试机制,提升请求成功率
- ✅ 统一响应: 封装
NbHttpResp对象,API 一致性强 - ✅ JSON 转换:
.dict属性直接获取 JSON 数据 - ✅ 智能日志: 集成
nb_log,自动记录错误和慢请求 - ✅ 灵活配置: 超时、重试、连接池等参数随心定制
📦 安装
pip install nb_aiohttp
⚡ 快速开始
🔹 异步模式 - 性能巅峰
完美适配 FastAPI、异步爬虫、高并发服务等场景:
import asyncio
from nb_aiohttp import NbAioHttpClient
# 🎯 在模块顶层直接实例化 - 这是最大的创新!
http = NbAioHttpClient(
timeout=10, # 超时时间
connector_limit=100, # 连接池大小
max_retries=3, # 最大重试次数
)
async def main():
# 🚀 发起 GET 请求 - 仅需一次 await
resp = await http.get('https://api.github.com/events')
print(f"状态码: {resp.status}")
print(f"响应内容: {resp.text[:100]}")
# 📤 发起 POST json数据请求 - API 简洁直观
resp = await http.post(
'https://httpbin.org/post',
json={'username': 'admin', 'password': '123456'}
)
# 🎁 直接获取 JSON 数据
print(f"响应数据: {resp.dict}")
# 🔐 使用 context manager 自动管理资源
async with NbAioHttpClient() as client:
resp = await client.get('https://www.python.org')
print(f"Python 官网: {resp.ok}")
# 🛑 手动关闭连接
await http.close()
if __name__ == '__main__':
asyncio.run(main())
🔹 同步模式 - 简单易用
完美适配传统 Django、Flask、爬虫脚本等同步场景:
from nb_aiohttp import NbSyncHttpClient
# 🎯 实例化同步客户端
http = NbSyncHttpClient(
timeout=10,
connector_limit=100,
max_retries=3,
)
# ⚙️ 启动后台事件循环(仅需调用一次)
http.run_forever()
# 🚀 像使用 requests 一样简单
resp = http.get('https://api.github.com/events')
print(f"状态码: {resp.status}")
print(f"响应内容: {resp.text[:100]}")
# 📤 POST 请求
resp = http.post(
'https://httpbin.org/post',
json={'key': 'value'}
)
print(f"响应数据: {resp.dict}")
# 🎯 无需手动关闭,自动管理生命周期
🔹 高级用法
错误处理与重试
from nb_aiohttp import NbAioHttpClient
http = NbAioHttpClient(
max_retries=5, # 失败后重试 5 次
is_raise_for_status=True, # 状态码异常时抛出错误
is_log_error=True, # 记录错误日志
)
async def robust_request():
try:
resp = await http.get('https://unstable-api.com/data')
return resp.dict
except Exception as e:
print(f"请求失败: {e}")
return None
性能监控
http = NbAioHttpClient(
log_timeout_seconds=2.0, # 超过 2 秒的请求将被记录
)
async def monitor_slow_requests():
# 慢请求会自动被记录到日志
resp = await http.get('https://slow-api.com/data')
自定义请求头和 Cookies
http = NbAioHttpClient(
headers={
'User-Agent': 'MyApp/1.0',
'Authorization': 'Bearer YOUR_TOKEN',
},
cookies={
'session_id': 'abc123',
}
)
async def custom_request():
# 使用全局配置的 headers 和 cookies
resp = await http.get('https://api.example.com/user')
# 或者临时覆盖
resp = await http.get(
'https://api.example.com/admin',
headers={'Authorization': 'Bearer ADMIN_TOKEN'}
)
完整的 HTTP 方法支持
http = NbAioHttpClient()
# 支持所有常用 HTTP 方法
await http.get(url)
await http.post(url, json=data)
await http.put(url, json=data)
await http.delete(url)
await http.patch(url, json=data)
await http.head(url)
await http.options(url)
📊 性能对比
实测数据
基于真实压测场景(200 并发,20万次请求):
| HTTP 客户端 | 异步性能 | 同步性能 | 易用性 | 全局实例化 |
|---|---|---|---|---|
| nb_aiohttp (异步) | ⚡⚡⚡⚡⚡ | - | ⭐⭐⭐⭐⭐ | ✅ |
| nb_aiohttp (同步) | - | ⚡⚡⚡⚡ | ⭐⭐⭐⭐⭐ | ✅ |
| aiohttp (原生) | ⚡⚡⚡⚡⚡ | - | ⭐⭐ | ❌ |
| httpx (异步) | ⚡ | - | ⭐⭐⭐⭐ | ✅ |
| httpx (同步) | - | ⚡⚡ | ⭐⭐⭐⭐ | ✅ |
| requests | - | ⚡ | ⭐⭐⭐⭐⭐ | ✅ |
性能结论
- 🏆 异步场景:
nb_aiohttp≈ 原生aiohttp>httpx(5倍) - 🏆 同步场景:
nb_aiohttp>httpx(2倍) >requests(4倍) - 🎯 易用性:
nb_aiohttp=requests>httpx> 原生aiohttp
代码对比
原生 aiohttp - 繁琐冗长
import aiohttp
import asyncio
async def fetch():
# ❌ 不能全局实例化
# ❌ 需要 2 次 async with
# ❌ 需要 3 次 await
async with aiohttp.ClientSession() as session:
async with session.get('https://api.github.com') as response:
if response.status == 200:
text = await response.text()
data = await response.json()
print(data)
nb_aiohttp - 极致简洁
from nb_aiohttp import NbAioHttpClient
import asyncio
# ✅ 全局实例化
http = NbAioHttpClient()
async def fetch():
# ✅ 仅需 1 次 await
# ✅ 自动处理状态码
# ✅ 直接获取数据
resp = await http.get('https://api.github.com')
print(resp.dict)
代码量减少 70%,可读性提升 300%!
📚 API 文档
NbAioHttpClient (异步客户端)
构造函数
NbAioHttpClient(
*,
timeout: int | float = 30,
connector_limit: int = 100,
max_retries: int = 3,
is_raise_for_status: bool = True,
log_timeout_seconds: int | float | None = None,
is_log_error: bool = True,
connector: BaseConnector = None,
headers: dict = None,
cookies: dict = None,
**kwargs
)
参数说明:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
timeout |
int/float | 30 | 请求超时时间(秒) |
connector_limit |
int | 100 | TCP 连接池大小 |
max_retries |
int | 3 | 失败重试次数 |
is_raise_for_status |
bool | True | 4xx/5xx 状态码是否抛异常 |
log_timeout_seconds |
int/float | None | 慢请求记录阈值(秒) |
is_log_error |
bool | True | 是否记录错误日志 |
connector |
BaseConnector | None | 自定义连接器 |
headers |
dict | None | 默认请求头 |
cookies |
dict | None | 默认 Cookies |
主要方法
# HTTP 请求方法
await http.get(url, **kwargs) -> NbHttpResp
await http.post(url, **kwargs) -> NbHttpResp
await http.put(url, **kwargs) -> NbHttpResp
await http.delete(url, **kwargs) -> NbHttpResp
await http.patch(url, **kwargs) -> NbHttpResp
await http.head(url, **kwargs) -> NbHttpResp
await http.options(url, **kwargs) -> NbHttpResp
# 通用请求方法
await http.request(method, url, **kwargs) -> NbHttpResp
# 生命周期管理
await http.ensure_session() # 确保 session 已创建
await http.close() # 关闭 session
# Context Manager 支持
async with NbAioHttpClient() as client:
resp = await client.get(url)
NbSyncHttpClient (同步客户端)
构造函数
NbSyncHttpClient(**kwargs) # 参数与 NbAioHttpClient 相同
主要方法
# 启动后台事件循环(必须首先调用)
http.run_forever()
# HTTP 请求方法(同步调用)
http.get(url, **kwargs) -> NbHttpResp
http.post(url, **kwargs) -> NbHttpResp
http.put(url, **kwargs) -> NbHttpResp
http.delete(url, **kwargs) -> NbHttpResp
http.patch(url, **kwargs) -> NbHttpResp
http.head(url, **kwargs) -> NbHttpResp
http.options(url, **kwargs) -> NbHttpResp
# 通用请求方法
http.request(method, url, **kwargs) -> NbHttpResp
NbHttpResp (响应对象)
统一封装的响应对象,提供便捷的数据访问接口:
class NbHttpResp:
text: str # 响应文本内容
status: int # HTTP 状态码
headers: dict # 响应头
url: str # 请求的 URL
@property
def dict(self) -> dict:
"""将 JSON 响应解析为字典"""
@property
def ok(self) -> bool:
"""状态码是否为 2xx"""
使用示例
resp = await http.get('https://api.github.com/users/github')
print(resp.status) # 200
print(resp.ok) # True
print(resp.text[:100]) # 响应文本前 100 字符
print(resp.dict['name']) # 直接访问 JSON 数据
print(resp.headers) # 响应头字典
print(resp.url) # 实际请求的 URL
🎯 使用场景
🔹 高并发 Web 服务
from fastapi import FastAPI
from nb_aiohttp import NbAioHttpClient
app = FastAPI()
http = NbAioHttpClient(connector_limit=500) # 全局实例
@app.get("/proxy")
async def proxy_request():
# 超高并发下依然稳定
resp = await http.get('https://api.example.com/data')
return resp.dict
🔹 异步爬虫
from nb_aiohttp import NbAioHttpClient
import asyncio
http = NbAioHttpClient(
timeout=30,
max_retries=5,
connector_limit=200,
)
async def crawl(url):
try:
resp = await http.get(url)
# 处理数据
return resp.text
except Exception as e:
print(f"爬取失败: {url}, 错误: {e}")
async def main():
urls = ['https://example.com/page' + str(i) for i in range(1000)]
tasks = [crawl(url) for url in urls]
results = await asyncio.gather(*tasks)
print(f"完成 {len(results)} 个页面的爬取")
asyncio.run(main())
🔹 微服务调用
from nb_aiohttp import NbAioHttpClient
# 不同服务的客户端
user_service = NbAioHttpClient(timeout=5)
order_service = NbAioHttpClient(timeout=10)
payment_service = NbAioHttpClient(timeout=15)
async def create_order(user_id, product_id):
# 并发调用多个服务
user_resp, product_resp = await asyncio.gather(
user_service.get(f'http://user-service/users/{user_id}'),
order_service.get(f'http://product-service/products/{product_id}')
)
# 创建订单
order_resp = await order_service.post(
'http://order-service/orders',
json={
'user': user_resp.dict,
'product': product_resp.dict,
}
)
return order_resp.dict
🔹 同步脚本
from nb_aiohttp import NbSyncHttpClient
http = NbSyncHttpClient().run_forever()
# 在任何同步代码中使用
def batch_process():
urls = ['https://api.example.com/item/' + str(i) for i in range(100)]
for url in urls:
resp = http.get(url)
if resp.ok:
print(f"处理成功: {resp.dict}")
else:
print(f"处理失败: {resp.status}")
batch_process()
🔧 高级配置
自定义 Connector
import aiohttp
from nb_aiohttp import NbAioHttpClient
# 自定义 SSL 和 DNS 配置
connector = aiohttp.TCPConnector(
limit=200,
ttl_dns_cache=300,
ssl=False,
)
http = NbAioHttpClient(connector=connector)
代理设置
http = NbAioHttpClient()
# 使用代理
resp = await http.get(
'https://api.example.com',
proxy='http://proxy.example.com:8080'
)
上传文件
http = NbAioHttpClient()
# 上传文件
with open('file.txt', 'rb') as f:
resp = await http.post(
'https://api.example.com/upload',
data={'file': f}
)
流式下载
http = NbAioHttpClient()
# 访问底层 aiohttp session 进行流式操作
await http.ensure_session()
async with http.session.get('https://example.com/large-file.zip') as response:
with open('downloaded.zip', 'wb') as f:
async for chunk in response.content.iter_chunked(1024):
f.write(chunk)
🤔 常见问题
Q: 为什么不直接使用 aiohttp?
A: 原生 aiohttp 虽然性能卓越,但 API 设计复杂:
- ❌ 不能在全局作用域实例化
ClientSession - ❌ 需要 2 次
async with和多次await - ❌ 缺少自动重试等企业级特性
nb_aiohttp 保留了 aiohttp 的性能优势,同时提供了更友好的 API。
Q: 与 httpx 相比有什么优势?
A:
- ⚡ 性能: 异步性能是 httpx 的 5 倍
- 🎯 简洁: API 设计更加简洁直观
- 🔄 灵活: 同时提供异步和同步两种模式
Q: NbSyncHttpClient 的性能为什么比 requests 好?
A: NbSyncHttpClient 底层使用 aiohttp 异步引擎,通过事件循环转换为同步接口,性能远超传统的同步阻塞模型。
Q: 是否支持 HTTP/2?
A: 目前基于 aiohttp,暂不支持 HTTP/2。如果你的场景强依赖 HTTP/2,建议使用 httpx。
Q: 如何处理请求失败?
A:
http = NbAioHttpClient(
max_retries=5, # 自动重试 5 次
is_raise_for_status=True # 失败时抛出异常
)
try:
resp = await http.get(url)
except Exception as e:
# 处理异常
print(f"请求失败: {e}")
📄 开源协议
本项目采用 MIT 协议 开源。
🙏 致谢
📮 联系方式
⭐ 如果这个项目对你有帮助,请给我们一个 Star!⭐
让 HTTP 请求更快、更简单、更优雅!
Made with ❤️ by ydf0509
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nb_aiohttp-1.1.tar.gz.
File metadata
- Download URL: nb_aiohttp-1.1.tar.gz
- Upload date:
- Size: 21.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.7.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d7a4027fa5281d70b88d055db457b749372a640494d6b403a4b3c629c7bf9c87
|
|
| MD5 |
ec172fabc3d4c36fdfd076451ef5786d
|
|
| BLAKE2b-256 |
bc1f278a772a89afdd2d66d5a327aab0f33aa0125be9ee078fab2c777dc1971f
|
File details
Details for the file nb_aiohttp-1.1-py3-none-any.whl.
File metadata
- Download URL: nb_aiohttp-1.1-py3-none-any.whl
- Upload date:
- Size: 10.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.7.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
52dcaad47ff43683a4882e1a1bfe29d2e678a622b84a4ee143e5f2ae42e00053
|
|
| MD5 |
d51b3c867c68672502594a5c24e0313f
|
|
| BLAKE2b-256 |
97e1672de019e90e733ecef08266f457c0d6cc28b155dda02d2413eee0fad7e3
|