3.2 实现 Qt Rest 网络拦截器

         本文是 《基于 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 则是被用来对网络请求、应答进行链式处理。

        链式处理借由 QPromise 展开,具体的拦截器在 intercept 方法内部一般会调用 processNext 来调用拦截器链的下一个拦截器的 intercept 方法。接着在异步获得 QNetworkReply 对象后,对其做进一步的处理,再异步的返回给前序拦截器。

        可以看出,对请求的拦截是从拦截器链的头部开始的,对与应答,则是反过来,最后一个拦截器先处理。

        拦截器一般有两种工作方式,一种是针对 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);
            });
        }
    });
}

        哪些错误不需要重试呢?它们是 HTTP 1xx,2xx,3xx。HTTP 1xx 表示临时应答,肯定不会出现;2xx 表示正常应答;3xx 表示请求错误,是我们发送的请求有问题,所以应该将错误交给外部去处理。

bool QRestRetryInterceptor::recoverable(QNetworkReply::NetworkError e)
{
    return e <= QNetworkReply::UnknownNetworkError || e >= QNetworkReply::ProtocolUnknownError;
}

最后的拦截器

        实际使用中,需要仔细安排拦截器的顺序,一般有下列顺序规则:在重试拦截器之前一些是业务相关的拦截器,之后则是需要完成网络配置,网络请求的拦截器。

        特别的,QRestClient 本身也是一个拦截器,并且永远在拦截器链的最后面。它发起实际的网络请求,等待应答完成(finished 信号),这种等待被转换为 QPromise 异步返回,这些在上一节已经讲过了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fighting Horse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值