auto close RequestUtils

This commit is contained in:
jxxghp
2025-06-27 08:30:57 +08:00
parent 9555ac6305
commit d8a53da8ee
2 changed files with 132 additions and 49 deletions
+10 -11
View File
@@ -4,7 +4,6 @@ from pathlib import Path
from typing import Optional, List, Dict from typing import Optional, List, Dict
import requests import requests
from requests import Response
from app import schemas from app import schemas
from app.core.cache import cached from app.core.cache import cached
@@ -77,7 +76,7 @@ class Alist(StorageBase, metaclass=Singleton):
token = conf.get("token") token = conf.get("token")
if token: if token:
return str(token) return str(token)
resp: Response = RequestUtils(headers={ resp = RequestUtils(headers={
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}).post_res( }).post_res(
self.__get_api_url("/api/auth/login"), self.__get_api_url("/api/auth/login"),
@@ -151,7 +150,7 @@ class Alist(StorageBase, metaclass=Singleton):
if item: if item:
return [item] return [item]
return [] return []
resp: Response = RequestUtils( resp = RequestUtils(
headers=self.__get_header_with_token() headers=self.__get_header_with_token()
).post_res( ).post_res(
self.__get_api_url("/api/fs/list"), self.__get_api_url("/api/fs/list"),
@@ -240,7 +239,7 @@ class Alist(StorageBase, metaclass=Singleton):
:param name: 目录名 :param name: 目录名
""" """
path = Path(fileitem.path) / name path = Path(fileitem.path) / name
resp: Response = RequestUtils( resp = RequestUtils(
headers=self.__get_header_with_token() headers=self.__get_header_with_token()
).post_res( ).post_res(
self.__get_api_url("/api/fs/mkdir"), self.__get_api_url("/api/fs/mkdir"),
@@ -304,7 +303,7 @@ class Alist(StorageBase, metaclass=Singleton):
:param per_page: 每页数量 :param per_page: 每页数量
:param refresh: 是否刷新 :param refresh: 是否刷新
""" """
resp: Response = RequestUtils( resp = RequestUtils(
headers=self.__get_header_with_token() headers=self.__get_header_with_token()
).post_res( ).post_res(
self.__get_api_url("/api/fs/get"), self.__get_api_url("/api/fs/get"),
@@ -381,7 +380,7 @@ class Alist(StorageBase, metaclass=Singleton):
""" """
删除文件 删除文件
""" """
resp: Response = RequestUtils( resp = RequestUtils(
headers=self.__get_header_with_token() headers=self.__get_header_with_token()
).post_res( ).post_res(
self.__get_api_url("/api/fs/remove"), self.__get_api_url("/api/fs/remove"),
@@ -425,7 +424,7 @@ class Alist(StorageBase, metaclass=Singleton):
""" """
重命名文件 重命名文件
""" """
resp: Response = RequestUtils( resp = RequestUtils(
headers=self.__get_header_with_token() headers=self.__get_header_with_token()
).post_res( ).post_res(
self.__get_api_url("/api/fs/rename"), self.__get_api_url("/api/fs/rename"),
@@ -476,7 +475,7 @@ class Alist(StorageBase, metaclass=Singleton):
:param path: 文件保存路径 :param path: 文件保存路径
:param password: 文件密码 :param password: 文件密码
""" """
resp: Response = RequestUtils( resp = RequestUtils(
headers=self.__get_header_with_token() headers=self.__get_header_with_token()
).post_res( ).post_res(
self.__get_api_url("/api/fs/get"), self.__get_api_url("/api/fs/get"),
@@ -561,7 +560,7 @@ class Alist(StorageBase, metaclass=Singleton):
headers.setdefault("As-Task", str(task).lower()) headers.setdefault("As-Task", str(task).lower())
headers.setdefault("File-Path", encoded_path) headers.setdefault("File-Path", encoded_path)
with open(path, "rb") as f: with open(path, "rb") as f:
resp: Response = RequestUtils(headers=headers).put_res( resp = RequestUtils(headers=headers).put_res(
self.__get_api_url("/api/fs/put"), self.__get_api_url("/api/fs/put"),
data=f, data=f,
) )
@@ -590,7 +589,7 @@ class Alist(StorageBase, metaclass=Singleton):
:param path: 目标目录 :param path: 目标目录
:param new_name: 新文件名 :param new_name: 新文件名
""" """
resp: Response = RequestUtils( resp = RequestUtils(
headers=self.__get_header_with_token() headers=self.__get_header_with_token()
).post_res( ).post_res(
self.__get_api_url("/api/fs/copy"), self.__get_api_url("/api/fs/copy"),
@@ -649,7 +648,7 @@ class Alist(StorageBase, metaclass=Singleton):
# 先重命名 # 先重命名
if fileitem.name != new_name: if fileitem.name != new_name:
self.rename(fileitem, new_name) self.rename(fileitem, new_name)
resp: Response = RequestUtils( resp = RequestUtils(
headers=self.__get_header_with_token() headers=self.__get_header_with_token()
).post_res( ).post_res(
self.__get_api_url("/api/fs/move"), self.__get_api_url("/api/fs/move"),
+122 -38
View File
@@ -13,6 +13,70 @@ from app.log import logger
urllib3.disable_warnings(InsecureRequestWarning) urllib3.disable_warnings(InsecureRequestWarning)
class AutoCloseResponse:
"""
自动关闭连接的Response包装器
在访问常用属性后自动关闭连接
"""
def __init__(self, response: Response):
self._response = response
self._closed = False
def __getattr__(self, name):
"""
对于其他属性,直接委托给原始response
"""
return getattr(self._response, name)
def _auto_close(self):
"""
自动关闭连接
"""
if not self._closed and self._response:
try:
self._response.close()
self._closed = True
except Exception as e:
logger.debug(f"自动关闭响应失败: {e}")
def json(self, **kwargs):
"""
获取JSON数据并自动关闭连接
"""
try:
data = self._response.json(**kwargs)
return data
finally:
self._auto_close()
@property
def text(self):
"""
获取文本内容并自动关闭连接
"""
try:
return self._response.text
finally:
self._auto_close()
@property
def content(self):
"""
获取二进制内容并自动关闭连接
"""
try:
return self._response.content
finally:
self._auto_close()
def close(self):
"""
手动关闭连接
"""
self._auto_close()
class RequestUtils: class RequestUtils:
def __init__(self, def __init__(self,
@@ -125,7 +189,8 @@ class RequestUtils:
json: dict = None, json: dict = None,
allow_redirects: bool = True, allow_redirects: bool = True,
raise_exception: bool = False, raise_exception: bool = False,
**kwargs) -> Optional[Response]: auto_close: bool = True,
**kwargs) -> Optional[AutoCloseResponse]:
""" """
发送GET请求并返回响应对象 发送GET请求并返回响应对象
:param url: 请求的URL :param url: 请求的URL
@@ -134,18 +199,22 @@ class RequestUtils:
:param json: 请求的JSON数据 :param json: 请求的JSON数据
:param allow_redirects: 是否允许重定向 :param allow_redirects: 是否允许重定向
:param raise_exception: 是否在发生异常时抛出异常,否则默认拦截异常返回None :param raise_exception: 是否在发生异常时抛出异常,否则默认拦截异常返回None
:param auto_close: 是否自动关闭响应连接,None时使用全局配置
:param kwargs: 其他请求参数,如headers, cookies, proxies等 :param kwargs: 其他请求参数,如headers, cookies, proxies等
:return: HTTP响应对象,若发生RequestException则返回None :return: HTTP响应对象,若发生RequestException则返回None
:raises: requests.exceptions.RequestException 仅raise_exception为True时会抛出 :raises: requests.exceptions.RequestException 仅raise_exception为True时会抛出
""" """
return self.request(method="get", response = self.request(method="get",
url=url, url=url,
params=params, params=params,
data=data, data=data,
json=json, json=json,
allow_redirects=allow_redirects, allow_redirects=allow_redirects,
raise_exception=raise_exception, raise_exception=raise_exception,
**kwargs) **kwargs)
if response is not None and auto_close:
return AutoCloseResponse(response)
return response
@contextmanager @contextmanager
def get_stream(self, url: str, params: dict = None, **kwargs): def get_stream(self, url: str, params: dict = None, **kwargs):
@@ -171,7 +240,8 @@ class RequestUtils:
files: Any = None, files: Any = None,
json: dict = None, json: dict = None,
raise_exception: bool = False, raise_exception: bool = False,
**kwargs) -> Optional[Response]: auto_close: bool = True,
**kwargs) -> Optional[AutoCloseResponse]:
""" """
发送POST请求并返回响应对象 发送POST请求并返回响应对象
:param url: 请求的URL :param url: 请求的URL
@@ -180,20 +250,24 @@ class RequestUtils:
:param allow_redirects: 是否允许重定向 :param allow_redirects: 是否允许重定向
:param files: 请求的文件 :param files: 请求的文件
:param json: 请求的JSON数据 :param json: 请求的JSON数据
:param kwargs: 其他请求参数,如headers, cookies, proxies等
:param raise_exception: 是否在发生异常时抛出异常,否则默认拦截异常返回None :param raise_exception: 是否在发生异常时抛出异常,否则默认拦截异常返回None
:param auto_close: 是否自动关闭响应连接,None时使用全局配置
:param kwargs: 其他请求参数,如headers, cookies, proxies等
:return: HTTP响应对象,若发生RequestException则返回None :return: HTTP响应对象,若发生RequestException则返回None
:raises: requests.exceptions.RequestException 仅raise_exception为True时会抛出 :raises: requests.exceptions.RequestException 仅raise_exception为True时会抛出
""" """
return self.request(method="post", response = self.request(method="post",
url=url, url=url,
data=data, data=data,
params=params, params=params,
allow_redirects=allow_redirects, allow_redirects=allow_redirects,
files=files, files=files,
json=json, json=json,
raise_exception=raise_exception, raise_exception=raise_exception,
**kwargs) **kwargs)
if response is not None and auto_close:
return AutoCloseResponse(response)
return response
def put_res(self, def put_res(self,
url: str, url: str,
@@ -203,7 +277,8 @@ class RequestUtils:
files: Any = None, files: Any = None,
json: dict = None, json: dict = None,
raise_exception: bool = False, raise_exception: bool = False,
**kwargs) -> Optional[Response]: auto_close: bool = True,
**kwargs) -> Optional[AutoCloseResponse]:
""" """
发送PUT请求并返回响应对象 发送PUT请求并返回响应对象
:param url: 请求的URL :param url: 请求的URL
@@ -213,19 +288,23 @@ class RequestUtils:
:param files: 请求的文件 :param files: 请求的文件
:param json: 请求的JSON数据 :param json: 请求的JSON数据
:param raise_exception: 是否在发生异常时抛出异常,否则默认拦截异常返回None :param raise_exception: 是否在发生异常时抛出异常,否则默认拦截异常返回None
:param auto_close: 是否自动关闭响应连接,None时使用全局配置
:param kwargs: 其他请求参数,如headers, cookies, proxies等 :param kwargs: 其他请求参数,如headers, cookies, proxies等
:return: HTTP响应对象,若发生RequestException则返回None :return: HTTP响应对象,若发生RequestException则返回None
:raises: requests.exceptions.RequestException 仅raise_exception为True时会抛出 :raises: requests.exceptions.RequestException 仅raise_exception为True时会抛出
""" """
return self.request(method="put", response = self.request(method="put",
url=url, url=url,
data=data, data=data,
params=params, params=params,
allow_redirects=allow_redirects, allow_redirects=allow_redirects,
files=files, files=files,
json=json, json=json,
raise_exception=raise_exception, raise_exception=raise_exception,
**kwargs) **kwargs)
if response is not None and auto_close:
return AutoCloseResponse(response)
return response
def delete_res(self, def delete_res(self,
url: str, url: str,
@@ -233,7 +312,8 @@ class RequestUtils:
params: dict = None, params: dict = None,
allow_redirects: bool = True, allow_redirects: bool = True,
raise_exception: bool = False, raise_exception: bool = False,
**kwargs) -> Optional[Response]: auto_close: bool = True,
**kwargs) -> Optional[AutoCloseResponse]:
""" """
发送DELETE请求并返回响应对象 发送DELETE请求并返回响应对象
:param url: 请求的URL :param url: 请求的URL
@@ -241,17 +321,21 @@ class RequestUtils:
:param params: 请求的参数 :param params: 请求的参数
:param allow_redirects: 是否允许重定向 :param allow_redirects: 是否允许重定向
:param raise_exception: 是否在发生异常时抛出异常,否则默认拦截异常返回None :param raise_exception: 是否在发生异常时抛出异常,否则默认拦截异常返回None
:param auto_close: 是否自动关闭响应连接,None时使用全局配置
:param kwargs: 其他请求参数,如headers, cookies, proxies等 :param kwargs: 其他请求参数,如headers, cookies, proxies等
:return: HTTP响应对象,若发生RequestException则返回None :return: HTTP响应对象,若发生RequestException则返回None
:raises: requests.exceptions.RequestException 仅raise_exception为True时会抛出 :raises: requests.exceptions.RequestException 仅raise_exception为True时会抛出
""" """
return self.request(method="delete", response = self.request(method="delete",
url=url, url=url,
data=data, data=data,
params=params, params=params,
allow_redirects=allow_redirects, allow_redirects=allow_redirects,
raise_exception=raise_exception, raise_exception=raise_exception,
**kwargs) **kwargs)
if response is not None and auto_close:
return AutoCloseResponse(response)
return response
@staticmethod @staticmethod
def cookie_parse(cookies_str: str, array: bool = False) -> Union[list, dict]: def cookie_parse(cookies_str: str, array: bool = False) -> Union[list, dict]: