Rest 网络拦截器
本文介绍 Qt Rest 网络框架中的拦截器,其基本接口定义如下:
class QTRESTCLIENT_EXPORT QRestInterceptor : public QObject
{
Q_OBJECT
public:
virtual void attached(QRestClient * client);
virtual void detached(QRestClient * client);
virtual QtPromise::QPromise<QNetworkReply *> intercept(QNetworkRequest & request) = 0;
};
当拦截器被加入到 QRestClient 以及从中删除时,其 attached、detached 方法会被调用。而 intercept 则是被用来对网络请求、应答进行链式处理。
拦截器一般有两种工作方式,一种是针对 QRestClient 的一次性配置,另一种是针对每一个请求的拦截处理。
代理配置拦截器(QRestProxyInterceptor)就是第一种拦截器,它的 attached 方法是这样的:
void QRestProxyInterceptor::attached(QRestClient *client)
{
client->setProxyUrl(url_);
client->removeInterceptor(this);
delete this;
}
在配置了 QRestClient 的代理后,立即从拦截器链中离开,所以其 intercept 是没有作用的。这种设计方式,减小了拦截器链的长度,从而能够提高对每个请求的处理效率。
重试拦截器
作为一个实现拦截器的例子,我们关注一下重试拦截器。当一个请求对应的应答失败了,重试拦截器会重启请求,直到超过重试次数,或者发生了不可(没有必要)重试的错误。
QPromise<QNetworkReply *> QRestRetryInterceptor::intercept(QNetworkRequest & request)
{
return process(request, times_);
}
QPromise<QNetworkReply *> QRestRetryInterceptor::process(QNetworkRequest & request, int times)
{
return processNext(request).then([this, times](QNetworkReply * reply) {
if (reply->error() == QNetworkReply::NoError) {
return QPromise<QNetworkReply *>::resolve(reply);
} else if (times == 0 || !recoverable(reply->error())) {
return QPromise<QNetworkReply *>::resolve(reply);
} else {
return QPromise<int>::resolve(0).delay(interval_).then([=]() {
QNetworkRequest request = reply->request();
reply->deleteLater();
return process(request, times - 1);
});
}
});
}
这里 processNext 是调用拦截器链的下一个拦截器的 intercept 方法。可以看出,对请求的拦截是从拦截器链的头部开始的,对与应答,则是反过来,最后一个拦截器先处理。
哪些错误不需要重试呢?它们是 HTTP 1xx,2xx,3xx。HTTP 1xx 表示临时应答,肯定不会出现;2xx 表示正常应答;3xx 表示请求错误,是我们发送的请求有问题,所以应该将错误交给外部去处理。
bool QRestRetryInterceptor::recoverable(QNetworkReply::NetworkError e)
{
return e <= QNetworkReply::UnknownNetworkError || e >= QNetworkReply::ProtocolUnknownError;
}