将 Python 与 PyQt 结合使用,我通过使用函数装饰器解决了类似的问题,该函数装饰器将请求保存在 lambda 函数中,并在失败时重新发送。在 C++ 中可能有类似的结构。
在我的特殊情况下,应用程序必须使用 OAuth2 系统,该系统分发的令牌仅在一小时内有效(并且无法刷新;隐式授权)。因此,可能是在这个小时后,用户会突然收到对他的一个请求的“未通过身份验证”响应,这当然不是真正的用户友好。所以我想,我会捕获这个 401 响应,让用户重新认证,然后重新发送最后一个失败的请求。
在我的 QNetworkAccessManager 子类中,我用一个名为 requires_internet_connection 的函数修饰了我的 HTTP 函数(get、put、post 等),因此我的 get 函数看起来像
@check_network_accessibility
def get(self, url, callback, *args, **kwargs):
""" Perform a HTTP GET request """
...
装饰器如下所示:
def check_network_accessibility(func):
""" Decorator function, not to be called directly.
Buffers the network request so that it can be sent again if it fails the first time, due to an invalidated
OAuth2 token. In this case the user will be presented with the login
screen again. If the *same* user successfully logs in again, the request
will be resent. """
@wraps(func)
def func_wrapper(inst, *args, **kwargs):
if inst.logged_in_user:
# Create an internal ID for this request
request_id=uuid.uuid4()
current_request = lambda: func(inst, *args, **kwargs)
# Add tuple with current user, and request to be performed
# to the pending request dictionary
inst.pending_requests[request_id] = (
inst.logged_in_user['data']['id'],
current_request)
# Add current request id to kwargs of function being called
kwargs['_request_id'] = request_id
return func(inst, *args, **kwargs)
return func_wrapper
总结起来,我检查用户是否登录,然后我将要发送的请求(完全包含传递的参数和所有)存储在 lambda 函数中,并将其存储在具有唯一 uuid 的 pending_requests 字典中钥匙。我将这个唯一的 uuid 注入到要调用的函数的 kwargs(带有键 _request_id)中,这样如果请求成功,我可以使用这个 uuid 将其从包含待处理请求的字典中删除(换句话说:向上)。如果完成没有问题,您可以在 QNetworkReply 的回调函数中执行此操作。
如果请求不成功,则会向用户显示一个登录窗口,如果他或她再次成功登录,则会调用一个函数,该函数会遍历待处理请求的字典并尝试再次执行:
def handle_login(self):
""" Handles the login event received after login. """
self.get_logged_in_user(self.set_logged_in_user)
def set_logged_in_user(self, user_data):
""" Callback function for handle_login; get_logged_in_user"""
# Parse received data about logged in user
self.logged_in_user = json.loads(safe_decode(user_data.readAll().data()))
# If user had any pending requests from previous login, execute them now
for (user_id, request) in self.pending_requests.values():
if user_id == self.logged_in_user['data']['id']:
request()
self.pending_requests = {}
我使用字典的原因是在 Qt 中可以并行发送多个请求,当然当用户必须重新进行身份验证时它们都会失败。我希望在同一用户再次登录后再次尝试所有这些。
正如我之前所说,我知道这是 Python,它的工作方式与 C++ 完全不同(我对此几乎一无所知),但我希望它能很好地说明原理,让人们想到 C++ 中的类似结构