3.2 实现 Qt Rest 网络拦截器

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;
}

上一篇:龟兔赛跑~


下一篇:简述jpg。Gif。png-8.png-24的区别,分别使用场景