Skip to main content

更好用的 aiohttp 客户端,支持同步和异步使用。 性能碾压 httpx 和 requests 400%

Project description

⚡ nb_aiohttp

下一代高性能 Python HTTP 客户端

Python Version License Performance

让异步请求像呼吸一样简单

特性安装快速开始性能对比API文档


💡 为什么选择 nb_aiohttp?

在 Python HTTP 客户端的世界里,我们常常面临一个艰难的选择:

  • 选择 requests?简单易用,但性能受限于同步阻塞
  • 选择 httpx?同步异步通吃,但性能平平
  • 选择 aiohttp?性能卓越,但 API 复杂,不能全局实例化

nb_aiohttp 横空出世,打破这个困局!

我们在 aiohttp 的强大性能基础上,重新设计了更友好的 API,让你既能享受极致性能,又能拥有极简体验。

🚀 核心特性

🏆 性能王者

  • 异步性能: 比 httpx5倍,完全释放 aiohttp 的性能潜力
  • 同步性能: 比 requests4倍,同步代码也能享受异步性能
  • 海量并发: 内置连接池管理,轻松应对数万级并发请求

🎯 极简设计

# 一行实例化,全局可用
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: 同步调用,适合非asyncio编程生态的传统应用、脚本

  • NbAioHttpClient的原理: 是调用aiohttpClientSession的异步方法 ,但使用方式被大幅简化,支持全局变量创建 NbAioHttpClient

  • NbSyncHttpClient的原理: 是通过 asyncio.run_coroutine_threadsafe 调用 NbAioHttpClient 的异步request方法,然后通过 future.result() 获取结果,所以本质也是在loop 中运行 aiohttp ,性能远超 requests

💪 企业级特性

  • 自动重试: 智能重试机制,提升请求成功率
  • 统一响应: 封装 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 协议 开源。

🙏 致谢

  • 感谢 aiohttp 提供了强大的异步 HTTP 引擎
  • 感谢 nb_log 提供了优秀的日志解决方案

📮 联系方式


⭐ 如果这个项目对你有帮助,请给我们一个 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

nb_aiohttp-1.2.tar.gz (27.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nb_aiohttp-1.2-py3-none-any.whl (10.8 kB view details)

Uploaded Python 3

File details

Details for the file nb_aiohttp-1.2.tar.gz.

File metadata

  • Download URL: nb_aiohttp-1.2.tar.gz
  • Upload date:
  • Size: 27.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.7.9

File hashes

Hashes for nb_aiohttp-1.2.tar.gz
Algorithm Hash digest
SHA256 9435117264eb48361e6ff0271bbd5ac8835fd358d6227fe0485d4fc9abf58240
MD5 34a381d6aa182d062611c7d9279ff5d0
BLAKE2b-256 74fb534711443c58aca416ad47708a842a868dec7016aab16b83a018399f65e6

See more details on using hashes here.

File details

Details for the file nb_aiohttp-1.2-py3-none-any.whl.

File metadata

  • Download URL: nb_aiohttp-1.2-py3-none-any.whl
  • Upload date:
  • Size: 10.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.7.9

File hashes

Hashes for nb_aiohttp-1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 623dbe89572c6c52738a3edab195765193063def06414fa48b55c545c02bdc4e
MD5 98317a09cf03091e1ebce99fb9da719a
BLAKE2b-256 92725a2356dc4853d95c994dd11d4f27d67d4a0cf65c06391a08334bdd2836c4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page