面对多个如DataReq
类依赖于LogSess
来维持会话的情况,为解决此问题,可以采用共享会话管理的策略。这样能确保登录操作仅在必要时发生,例如当cookie过期、页面提示“您必须登录”,或是首次实例化LogSess
时。
解决这个问题的一个途径是,对LogSess
应用单例模式,并实现会话验证与刷新机制(类似于@VonC的方案,但未包含后续部分)。为何如此做?
- 采用单例模式实现
LogSess
确保了仅创建一个实例,并且所有后续请求都复用这个实例,从而登录流程仅在首次或按需(根据OP提到的条件)发生。其次,通过在LogSess
中加入会话验证和刷新的方法,可以依据cookie过期或特定响应内容指示登录要求来判断会话是否有效及是否需要重新登录。
以下是相应的代码实现:
import requests
from json import JSONDecodeError
URL_LOGIN = "https://www/login..."
URL_TDATA = "https://www/services..."
class LogSess:
_instance = None
def __new__(cls, username="foo", password="bar"):
if cls._instance is None:
cls._instance = super(LogSess, cls).__new__(cls)
cls._instance.session = requests.Session()
cls._instance.username = username
cls._instance.password = password
cls._instance.login()
return cls._instance
def login(self):
self.session.post(URL_LOGIN, data={"login": self.username, "password": self.password})
def refresh_session(self):
# 在这里检查cookie是否过期或响应内容是否需要登录
# 如有必要,调用self.login()
class DataReq:
def __init__(self, name):
self.name = name
self._data = None
@property
def data(self):
if self._data is None:
log_sess = LogSess()
response = log_sess.session.post(URL_TDATA, data={"name": self.name})
try:
self._data = response.json()
except JSONDecodeError:
print("会话已过期!需要重新登录。")
log_sess.refresh_session()
self._data = log_sess.session.post(URL_TDATA, data={"name": self.name}).json()
return self._data
# 使用示例
data_request = DataReq("example")
print(data_request.data)
在这个实现中,LogSess
被设计为单例,首次实例化时调用登录方法,而refresh_session
方法可根据需要检查并刷新会话。DataReq
类使用LogSess
的实例来获取会话并处理数据请求,包括在必要时刷新会话。
单例模式提供了一个全局访问点,这对于管理如会话处理这类共享资源特别有用(应避免为管理共享资源的类创建多个实例)。
当然,需要注意的是,虽然单例模式在某些应用场景(如会话管理)中非常有用,但因其可能导致测试难度增加及滥用全局变量的风险,有时也被视为反模式。因此,在使用时应谨慎,并充分理解其对应用程序的影响。