http_client.py 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import aiohttp
  2. from typing import Optional, Union, Dict, Any
  3. class AsyncHttpClient:
  4. """异步 HTTP 客户端,基于 aiohttp,支持连接池和超时配置"""
  5. def __init__(
  6. self,
  7. timeout: int = 10,
  8. max_connections: int = 100,
  9. default_headers: Optional[Dict[str, str]] = None,
  10. ):
  11. self.timeout = aiohttp.ClientTimeout(total=timeout)
  12. self.connector = aiohttp.TCPConnector(limit=max_connections)
  13. self.default_headers = default_headers or {}
  14. self.session = None
  15. async def __aenter__(self):
  16. self.session = aiohttp.ClientSession(
  17. connector=self.connector,
  18. timeout=self.timeout,
  19. headers=self.default_headers,
  20. )
  21. return self
  22. async def __aexit__(self, exc_type, exc_val, exc_tb):
  23. await self.session.close()
  24. async def request(
  25. self,
  26. method: str,
  27. url: str,
  28. params: Optional[Dict[str, Any]] = None,
  29. data: Optional[Union[Dict[str, Any], str, bytes]] = None,
  30. json: Optional[Dict[str, Any]] = None,
  31. headers: Optional[Dict[str, str]] = None,
  32. ) -> Union[Dict[str, Any], str]:
  33. """核心请求方法"""
  34. request_headers = {**self.default_headers, **(headers or {})}
  35. try:
  36. async with self.session.request(
  37. method,
  38. url,
  39. params=params,
  40. data=data,
  41. json=json,
  42. headers=request_headers,
  43. ) as response:
  44. response.raise_for_status()
  45. content_type = response.headers.get("Content-Type", "")
  46. if "application/json" in content_type:
  47. return await response.json()
  48. return await response.text()
  49. except aiohttp.ClientResponseError as e:
  50. print(f"HTTP error: {e.status} {e.message}")
  51. raise
  52. except aiohttp.ClientError as e:
  53. print(f"Network error: {str(e)}")
  54. raise
  55. async def get(
  56. self,
  57. url: str,
  58. params: Optional[Dict[str, Any]] = None,
  59. headers: Optional[Dict[str, str]] = None,
  60. ) -> Union[Dict[str, Any], str]:
  61. """GET 请求"""
  62. return await self.request("GET", url, params=params, headers=headers)
  63. async def post(
  64. self,
  65. url: str,
  66. data: Optional[Union[Dict[str, Any], str, bytes]] = None,
  67. json: Optional[Dict[str, Any]] = None,
  68. headers: Optional[Dict[str, str]] = None,
  69. ) -> Union[Dict[str, Any], str]:
  70. """POST 请求"""
  71. return await self.request("POST", url, data=data, json=json, headers=headers)
  72. async def put(
  73. self,
  74. url: str,
  75. data: Optional[Union[Dict[str, Any], str, bytes]] = None,
  76. json: Optional[Dict[str, Any]] = None,
  77. headers: Optional[Dict[str, str]] = None,
  78. ) -> Union[Dict[str, Any], str]:
  79. """PUT 请求"""
  80. return await self.request("PUT", url, data=data, json=json, headers=headers)