QNetworkAccessManager、QNetworkRequest和QNetworkReply与http通讯

82 篇文章 1 订阅

QNetworkAccessManager、QNetworkRequest和QNetworkReply三者关系:
QNetworkAccessManager是主体,它负责发送和接收,也就是get和post,并且他还能判断网络连接状态,通过networkSessionConnected信号判断。
QNetworkRequest是请求,它是要访问的内容,并且它也能对这些内容进行配置,它放在QNetworkAccessManager的get和post中使用。
QNetworkReply它是回复,即返回结果,它能获取到get,post后得到的结果,包括正常的和异常的。
拓展:QSslConfiguration它是QNetworkRequest的一个访问设置类,如下设置协议类型支持https:

  QNetworkRequest req(url);
  QSslConfiguration config;

  config.setPeerVerifyMode(QSslSocket::VerifyNone);
  config.setProtocol(QSsl::AnyProtocol);
  req.setSslConfiguration(config);

QNetworkRequest可以通过设置head来设置发送类型的格式,如下:
字符串模式:

  req.setHeader(QNetworkRequest::ContentTypeHeader,
                QVariant("application/x-www-form-urlencoded"));

json模式:

  req.setHeader(QNetworkRequest::ContentTypeHeader,
                QVariant("application/json"));

这里简单介绍下QNetworkAccessManager的get和post,它们都是访问服务器,但是get一般是不带参数的,post一般会有参数的。当然get也可以带参数,例如QNetworkRequest设置的url里面带有参数,例如这种格式:http://testurl?id=666&name=“xiaoming”;

QNetworkReply作为获取返回值和获取连接状态来使用,它可以同步获取,也可以异步获取。
同步获取:使用QEventloop来做一个非阻塞延时。
异步获取:通过关联信号readyRead来获取。
同步访问后台使用实例:
.h

#ifndef HTTPCLIENT_H
#define HTTPCLIENT_H

#include <QNetworkAccessManager>
#include <QObject>

class HttpClient : public QObject {
  Q_OBJECT
public:
  HttpClient(QObject *parent = 0);

  QByteArray get(const QString &url, int timeout);

  QByteArray post(const QString &url, const QByteArray &data, int timeout);

  QByteArray posttojson(const QString &url, const QByteArray &data, int timeout);
private slots:
  void replyFinished(QNetworkReply *reply);

protected:
  QByteArray request(QNetworkReply *reply, int timeout);

private:
  QNetworkAccessManager *m_manager;
  QString m_recvData;
};

#endif // HTTPCLIENT_H

cpp:

#include "httpclient.h"
#include <QDebug>
#include <QEventLoop>
#include <QNetworkReply>
#include <QSslConfiguration>
#include <QTextCodec>
#include <QTimer>
#define HTTP_HEADER_KEY       "X-Version"
#define HTTP_HEADER_VALUE       "1.0"

HttpClient::HttpClient(QObject *parent) : QObject(parent) {
  m_recvData = "";
  m_manager = new QNetworkAccessManager(this);
  connect(m_manager, SIGNAL(finished(QNetworkReply *)), this,
          SLOT(replyFinished(QNetworkReply *)));
}

QByteArray HttpClient::get(const QString &url, int timeout) {
  QNetworkRequest req(url);
  //下边的四行代码是做验证处理的,方式不止这一种
  QSslConfiguration config;

  config.setPeerVerifyMode(QSslSocket::VerifyNone);
  config.setProtocol(QSsl::AnyProtocol);
  req.setSslConfiguration(config);
  req.setRawHeader(HTTP_HEADER_KEY,
                    HTTP_HEADER_VALUE);
  req.setHeader(QNetworkRequest::ContentTypeHeader,
                QVariant("application/x-www-form-urlencoded"));
  return request(m_manager->get(req), timeout);
}

QByteArray HttpClient::post(const QString &url, const QByteArray &data,
                            int timeout) {
  QNetworkRequest req(url);
  //下边的四行代码是做验证处理的,方式不止这一种
  QSslConfiguration config;

  config.setPeerVerifyMode(QSslSocket::VerifyNone);
  config.setProtocol(QSsl::AnyProtocol);
  req.setSslConfiguration(config);
  req.setRawHeader(HTTP_HEADER_KEY,
                    HTTP_HEADER_VALUE);
  req.setHeader(QNetworkRequest::ContentTypeHeader,
                QVariant("application/x-www-form-urlencoded"));
  return request(m_manager->post(req, data), timeout);
}

QByteArray HttpClient::posttojson(const QString &url, const QByteArray &data,
                            int timeout) {
  QNetworkRequest req(url);
  //下边的四行代码是做验证处理的,方式不止这一种
  QSslConfiguration config;

  config.setPeerVerifyMode(QSslSocket::VerifyNone);
  config.setProtocol(QSsl::AnyProtocol);
  req.setSslConfiguration(config);
  req.setRawHeader(HTTP_HEADER_KEY,
                    HTTP_HEADER_VALUE);
  req.setHeader(QNetworkRequest::ContentTypeHeader,
                QVariant("application/json"));
  return request(m_manager->post(req, data), timeout);
}

void HttpClient::replyFinished(QNetworkReply *reply) {
  QVariant status_code =
      reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);

  QByteArray bytes = reply->readAll();
  QTextCodec *pCodec = QTextCodec::codecForName("UTF-8");
  m_recvData = pCodec->toUnicode(bytes);

  if (reply->error() != QNetworkReply::NoError) {
    qWarning() << "http通信返回错误" <<reply->url()<<status_code;
  }
  reply->deleteLater(); //要删除reply,要调用deletelater;
}

QByteArray HttpClient::request(QNetworkReply *reply, int timeout) {
  QEventLoop loop;
  QTimer timer;
  connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
  connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
  timer.start(timeout);
  loop.exec();
  return m_recvData.toUtf8();
}

从服务器下载文件实例:
.h

#ifndef HTTPDOWNLOADBUSSSINESS_H
#define HTTPDOWNLOADBUSSSINESS_H

#include <QObject>

#include <QFile>
#include <QNetworkReply>
#include <QObject>

class Reply;

class HttpDownloadBussiness : public QObject {
    Q_OBJECT
public:
    HttpDownloadBussiness (QString url,QString fileName,QObject *parent = 0);

    //  bool getRunningStatus() const;
public slots:
    bool download();

    //  bool stopDownload(QString url);

public slots:
    void handleFinished();
    void handleReadyRead();
    void updateDownloadProgress(qint64, qint64);
    void handleError(QNetworkReply::NetworkError error);

private:
    bool raiseFailed();
    void raiseCompleted();
    //  void raiseStop();
signals:
    void progressChangedSig(quint64 p, quint64 t);
    void downloadCompletedSig();
    void downloadFailedSig();
    //  void downloadStopSig();

private:
    QNetworkAccessManager *m_manager;
    QNetworkReply *m_netReply;
    Reply *m_reply;
    quint64 m_total;
    bool m_isRunning;
    QFile *m_file;
    QUrl m_url;
    QString m_fileTemp;
    qint64 m_existSize;
    //  bool m_isStop;
};

class Reply : public QObject {
    Q_OBJECT

public:
    Reply(QNetworkReply *reply);
    enum { Head, Get };

    int method() const { return m_method; }

    void setMethod(int method) { m_method = method; }

    void abort() { m_reply->abort(); }

    QVariant header(QNetworkRequest::KnownHeaders header) const {
        return m_reply->header(header);
    }

    QNetworkReply *reply() const { return m_reply; }
    quint64 current;
signals:
    void finished();
    void errorOccurred(QNetworkReply::NetworkError);
    void readyRead();
    void updateDownloadProgress(qint64, qint64);

private:
    QNetworkReply *m_reply;
    int m_method;
};

#endif // HTTPDOWNLOADBUSSSINESS_H

.cpp

#include "httpdownloadbussiness.h"
#include <QDebug>
#include <QFile>
#include <QSslConfiguration>
#include <QThread>
#include <QTimerEvent>

HttpDownloadBussiness ::HttpDownloadBussiness(QString url,QString fileName,QObject *parent) : QObject(parent) {
    m_isRunning = false;
    m_url = QUrl(url);
    m_fileTemp = fileName + "_tmp";
    //    m_isStop = false;

}

bool HttpDownloadBussiness ::download() {
    m_manager = new QNetworkAccessManager;
    m_isRunning = true;
    m_existSize = 0;

    m_file = new QFile(m_fileTemp, this);
    if (!m_file->open(QFile::WriteOnly | QIODevice::Append)) {
        raiseFailed();
        return false;
    }

    QNetworkRequest req(m_url);
    //下边的四行代码是做验证处理的,方式不止这一种
    QSslConfiguration config;
    config.setPeerVerifyMode(QSslSocket::VerifyNone);
    config.setProtocol(QSsl::AnyProtocol);
    req.setSslConfiguration(config);
    QNetworkAccessManager *accessManager = new QNetworkAccessManager(this);
    qDebug() << "当前支持协议:"<<accessManager->supportedSchemes();

//    req.setRawHeader("Range", pos.toLatin1());

    //  if (m_manager->networkAccessible() == QNetworkAccessManager::NotAccessible) {
    //    m_manager->setNetworkAccessible(QNetworkAccessManager::Accessible);
    //  }

    m_reply = new Reply(m_manager->get(req));

    m_reply->current = 0;
    qWarning() << QString::fromUtf8("%1文件开始下载...").arg(m_fileTemp)<<m_url;

    connect(m_reply, SIGNAL(readyRead()), this, SLOT(handleReadyRead()));
    connect(m_reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this,
            SLOT(handleError(QNetworkReply::NetworkError)));
    connect(m_reply, SIGNAL(finished()), this, SLOT(handleFinished()));
    connect(m_reply,SIGNAL(finished()), m_reply, SLOT(deleteLater()));
    connect(m_reply, SIGNAL(updateDownloadProgress(qint64, qint64)), this,
            SLOT(updateDownloadProgress(qint64, qint64)));

    return true;
}

#if 0
bool HttpDownloadBussiness ::stopDownload(QString url) {
    if (m_url == QUrl(url)) {
        m_isRunning = false;
        if (m_reply && !m_isStop) {
            disconnect(m_reply, SIGNAL(readyRead()), this, SLOT(handleReadyRead()));
            disconnect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), this,
                       SLOT(handleError(QNetworkReply::NetworkError)));
            disconnect(m_reply, SIGNAL(finished()), this, SLOT(handleFinished()));
            disconnect(m_reply, SIGNAL(finished()), m_reply, SLOT(deleteLater()));
            disconnect(m_reply, SIGNAL(updateDownloadProgress(qint64, qint64)), this,
                       SLOT(updateDownloadProgress(qint64, qint64)));
            if (!m_isStop)
            {
                m_reply->reply()->abort();
                if (m_reply)
                    m_reply->reply()->deleteLater();
                m_isStop = true;
            }
        }
        emit downloadStopSig();
        return true;
    }
    return false;
}

bool HttpDownloadBussiness ::getRunningStatus() const { return m_isRunning; }
#endif

void HttpDownloadBussiness ::handleFinished() {
    if (m_isRunning)
    {
        //        m_isStop = true;
        m_file->close();
        int index = m_fileTemp.lastIndexOf("_tmp");
        QString realName = m_fileTemp.left(index);
        bool ok = QFile::rename(m_fileTemp, realName);
        qWarning() <<__FUNCTION__ << __LINE__<<QStringLiteral("下载完成:")<<m_fileTemp;
        raiseCompleted();
    }
}

void HttpDownloadBussiness ::handleReadyRead() {

    Reply *reply = qobject_cast<Reply *>(sender());
    QByteArray content = reply->reply()->readAll();

    m_file->seek(reply->current);
    m_file->write(content);
    reply->current += content.length();
}

void HttpDownloadBussiness ::updateDownloadProgress(qint64 part, qint64 total) {
//    qDebug()<<QStringLiteral("下载进度:")<<(part+m_existSize)/1024.00/1024.00<<QStringLiteral("总大小:")<<(total+m_existSize)/1024.00/1024.00;
    if (m_isRunning)
        emit progressChangedSig(part + m_existSize, total + m_existSize);
}

void HttpDownloadBussiness ::handleError(QNetworkReply::NetworkError error) {
    qDebug() << "http error:" << error;
    if (error != QNetworkReply::NoError && error != QNetworkReply::UnknownContentError) {
        qDebug() << "http error:" << error;
        m_isRunning = false;
        m_file->close();

        //暂时屏蔽该代码,使用恢复下载超时处理,
        if (!QFile::remove(m_file->fileName())) {
            qDebug() << "remove failed";
        }
    }
    emit downloadFailedSig();
}


bool HttpDownloadBussiness ::raiseFailed() {
    m_isRunning = false;
    m_file->close();
    if (!QFile::remove(m_file->fileName())) {
        qDebug() << "create remove failed";
    }
    emit downloadFailedSig();
    return false;
}

void HttpDownloadBussiness ::raiseCompleted() {
    m_isRunning = false;
    connect(m_manager, SIGNAL(finished(QNetworkReply *)), m_manager,
            SLOT(deleteLater()));
    emit downloadCompletedSig();
}

#if 0
void HttpDownloadBussiness ::raiseStop() { emit downloadStopSig(); }
#endif

Reply::Reply(QNetworkReply *reply) {
    m_reply = reply;
    qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
    connect(m_reply, SIGNAL(finished()), this, SIGNAL(finished()));
    connect(m_reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this,
            SIGNAL(errorOccurred(QNetworkReply::NetworkError)));
    connect(m_reply, SIGNAL(readyRead()), this, SIGNAL(readyRead()));
    connect(m_reply, SIGNAL(downloadProgress(qint64, qint64)), this,
            SIGNAL(updateDownloadProgress(qint64, qint64)));
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

东方忘忧

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

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

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

打赏作者

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

抵扣说明:

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

余额充值