使用Qt通过HTTP请求数据(post和get)

我当前使用的Qt版本是5.5.1 该版本的HTTP相关处理模块在遇到重定向的时候不会自动重定向,需要手工处理,我在这个例子中处理了这种方式。

话不多说我直接上示例代码了:

类名:CHttpSupport

.h文件

#ifndef CHTTPSUPPORT_H
#define CHTTPSUPPORT_H

#include <QNetworkAccessManager>

class CHttpSupport: public QObject
{
    Q_OBJECT
private:
    CHttpSupport(QObject* parent = NULL);
    ~CHttpSupport();

private:
    //
    static CHttpSupport*      gInstance;
    //

    //
    QNetworkAccessManager*    mNetAccessManager;
    QString                   mCacheRoot;                   //* 缓存目录
    QMap<QString, bool>       mProcessingRq;                //* 当前正在处理的请求url 和是否正在处理
    QMap<QString, QByteArray> mDownloadDataCache;           //* 数据缓存url -> data | postMD5 -> data
    QMap<QString, QString>    mRedirectMap;                 //* 重定向关系
    //

signals:
    ///
    /// \brief httpGetRspReady http get 请求得到回复
    /// \param url             请求的地址
    /// \param data            回复的数据(如果isEmpty则表示请求出错了)
    ///
    void httpGetRspReady(QString url, QByteArray data);

    ///
    /// \brief httpPostRspReady http post 请求得到回复
    /// \param url              请求的地址
    /// \param postMD5          是post的时候url+数据的md5
    /// \param data             data是回复的数据(如果isEmpty则表示请求出错了)
    ///
    void httpPostRspReady(QString url, QString postMD5, QByteArray data);

private slots:
    void clearRp(QNetworkReply* rp);

    void onHttpGetRspProgress(qint64 bytesReceived, qint64 bytesTotal); //* http get 回复进度
    void onHttpGetRspFinished(); //* http get 处理完毕

    void onHttpPostRspProgress(qint64 bytesReceived, qint64 bytesTotal); //* http post 回复进度
    void onHttpPostRspFinished(); //* http get 处理完毕

public:
    /
    static CHttpSupport* instance       ();
    static bool          hasInstance    ();
    static void          releaseInstance();
    /

    /
    /// \brief httpGet 发起一个http get 请求
    /// \param url     请求地址
    ///
    void httpGet(const QString& url);

    ///
    /// \brief httpPost 发起一个http post 请求
    /// \param url      是请求的链接
    /// \param data     是传送的数据
    /// \return         返回url+data的md5
    ///
    QByteArray httpPost(const QString& url, const QByteArray &data);

};

#endif // CHTTPSUPPORT_H

接下来是.cpp文件

#include "CHttpSupport.h"

#include <QCryptographicHash>
#include <QStandardPaths>
#include <QFile>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QImage>
#include <QDir>

CHttpSupport* CHttpSupport::gInstance = 0;

CHttpSupport::CHttpSupport(QObject *parent)
    :QObject(parent)
    ,mNetAccessManager(new QNetworkAccessManager(this))
{

}

CHttpSupport::~CHttpSupport()
{

}

void CHttpSupport::clearRp(QNetworkReply *rp)
{
    if(rp)
    {
        QString url = rp->request().url().toString();
        QString postMD5 = rp->property("postMD5").toString();
        QString postData = rp->property("data").toByteArray();

        if(postMD5.isEmpty())
        {
            //清理对应缓存
            mDownloadDataCache.remove(url);

            //解除正在处理状态
            mProcessingRq.remove(url);
        }
        else
        {
            //清理对应缓存
            mDownloadDataCache.remove(postMD5);


            //解除正在处理状态
            mProcessingRq.remove(postMD5);
        }

        mRedirectMap.remove(url);
        mRedirectMap.remove(postMD5);

        qDebug() << "delete cache, url:" << url << " postMOD5:" << postMD5;
        rp->deleteLater();
    }
}

void CHttpSupport::onHttpGetRspProgress(qint64 bytesReceived, qint64 bytesTotal)
{
    if(sender() == NULL)
    {
        return ;
    }

    QNetworkReply* rp = qobject_cast<QNetworkReply*>(sender());
    if(rp == NULL)
    {
        return;
    }

    qDebug() << "http get rsp progress:" << rp->url().toString() << bytesReceived << "/" << bytesTotal;
    if(bytesTotal <= 0)
    {
        return;
    }

    QString url = rp->url().toString();

    mDownloadDataCache[url].append(rp->readAll());

}

void CHttpSupport::onHttpGetRspFinished()
{
    if(sender() == NULL)
    {
        return ;
    }

    QNetworkReply* rp = qobject_cast<QNetworkReply*>(sender());
    if(rp == NULL)
    {
        return;
    }

    QByteArray rpData;
    QString url = rp->url().toString();


    int statusCode = rp->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    QString strUrl = rp->attribute(QNetworkRequest::RedirectionTargetAttribute).toString();

    switch(statusCode)
    {
    case 200: // ok
    {
        rpData = mDownloadDataCache[rp->url().toString()];

        QString redirectUrl = mRedirectMap[url];
        if(redirectUrl.isEmpty())
        {
            qDebug() << "http get rsp ok:" << url << "total size:" << rpData.count() << "bytes";
            emit httpGetRspReady(url, rpData);
        }
        else
        {
            qDebug() << "http get rsp ok:" << url << "total size:" << rpData.count() << "bytes" << "[redirect by]" << redirectUrl;
            emit httpGetRspReady(redirectUrl, rpData);
        }

    }
        break;
    case 301:
    case 302: // redirect
    {
        if(!strUrl.isEmpty())
        {
            QString turl = mRedirectMap[url];
            if(turl.isEmpty())
                mRedirectMap[strUrl] = url;
            else
                mRedirectMap[strUrl] = turl;

            httpGet(strUrl);
        }
    }
        break;
    default: // error
    {
        qDebug() << url << "[get error:" << statusCode << "]";
        QString redirectUrl = mRedirectMap[url];
        if(redirectUrl.isEmpty())
        {
            emit httpGetRspReady(url, QByteArray());
        }
        else
        {
            emit httpGetRspReady(redirectUrl, QByteArray());
        }
    }
        break;
    }

    clearRp(rp);
}

void CHttpSupport::onHttpPostRspProgress(qint64 bytesReceived, qint64 bytesTotal)
{
    if(sender() == NULL)
    {
        return ;
    }

    QNetworkReply* rp = qobject_cast<QNetworkReply*>(sender());
    if(rp == NULL)
    {
        return;
    }

    qDebug() << "http post rsp progress:" << rp->url().toString() << bytesReceived << "/" << bytesTotal;
    if(bytesTotal <= 0)
    {
        return;
    }

    QString postMD5 = rp->property("postMD5").toString();

    mDownloadDataCache[postMD5].append(rp->readAll());
}

void CHttpSupport::onHttpPostRspFinished()
{
    if(sender() == NULL)
    {
        return ;
    }

    QNetworkReply* rp = qobject_cast<QNetworkReply*>(sender());
    if(rp == NULL)
    {
        return;
    }

    QByteArray rpData;

    QString url = rp->url().toString();
    QString postMD5 = rp->property("postMD5").toString();
    QByteArray postData = rp->property("data").toByteArray();

    int statusCode = rp->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    QString strUrl = rp->attribute(QNetworkRequest::RedirectionTargetAttribute).toString();

    switch(statusCode)
    {
    case 200:
        {
            rpData = mDownloadDataCache[postMD5];

            QString redirectMD5 = mRedirectMap[postMD5];
            QString redirectUrl = mRedirectMap[url];
            if(redirectMD5.isEmpty() || redirectUrl.isEmpty())
            {
                qDebug() << "http post rsp ok:" << url << "total size:" << rpData.count() << "bytes";
                emit httpPostRspReady(url, postMD5, rpData);
            }
            else
            {
                qDebug() << "http post rsp ok:" << url << "total size:" << rpData.count() << "bytes" << "[redirect by]" << redirectUrl << "[data]" << postData;
                emit httpPostRspReady(redirectUrl, redirectMD5, rpData);
            }

        }
        break;
    case 301:
    case 302:
        {
            if(!strUrl.isEmpty())
            {
                QString turl = mRedirectMap[url];//direct by
                if(turl.isEmpty())
                    mRedirectMap[strUrl] = url;
                else
                    mRedirectMap[strUrl] = turl;


                QByteArray d;
                d.append(strUrl);
                d.append(postData);
                QString md5 = QCryptographicHash::hash(d, QCryptographicHash::Md5);
                QString tPostMD5 = mRedirectMap[md5];//direct by
                if(tPostMD5.isEmpty())
                {
                    mRedirectMap[md5] = postMD5;
                }
                else
                {
                    mRedirectMap[md5] = tPostMD5;
                }


                httpPost(strUrl, postData);
            }
        }
        break;
    default:
        qDebug() << url << "[post error:" << statusCode << "]";
        QString redirectMD5 = mRedirectMap[postMD5];
        QString redirectUrl = mRedirectMap[url];
        if(redirectMD5.isEmpty() || redirectUrl.isEmpty())
        {
            emit httpPostRspReady(url, postMD5, QByteArray());
        }
        else
        {
            emit httpPostRspReady(redirectUrl, redirectMD5, QByteArray());
        }
        break;
    }

    clearRp(rp);
}

CHttpSupport *CHttpSupport::instance()
{
    if(!gInstance)
        gInstance = new CHttpSupport;

    return gInstance;
}

bool CHttpSupport::hasInstance()
{
    return gInstance != NULL;
}

void CHttpSupport::releaseInstance()
{
    if(gInstance)
        delete gInstance;

    gInstance = NULL;
}

void CHttpSupport::httpGet(const QString &url)
{
    if(mProcessingRq.value(url, false)) //ignore when rq processing
    {
        return;
    }

    for(int i = 0; i < mRedirectMap.values().count(); i++)
    {
        if(mRedirectMap.values()[i] == url) //ignore when redirect processing
        {
            return;
        }
    }

    mProcessingRq.insert(url, true);

    QNetworkRequest rq;
    QSslConfiguration config = rq.sslConfiguration();
    config.setPeerVerifyMode(QSslSocket::VerifyNone);
    config.setProtocol(QSsl::TlsV1SslV3);
    rq.setSslConfiguration(config);

    rq.setUrl(QUrl(url));
    QNetworkReply* rp = mNetAccessManager->get(rq);
    connect(rp, &QNetworkReply::finished        , this, &CHttpSupport::onHttpGetRspFinished);
    connect(rp, &QNetworkReply::downloadProgress, this, &CHttpSupport::onHttpGetRspProgress);
}

QByteArray CHttpSupport::httpPost(const QString &url, const QByteArray &data)
{
    QByteArray d;
    d.append(url);
    d.append(data);
    QByteArray md5 = QCryptographicHash::hash(d, QCryptographicHash::Md5);

    if(mProcessingRq.value(md5, false)) //ignore when rq processing
    {
        return md5;
    }

    for(int i = 0; i < mRedirectMap.values().count(); i++)
    {
        if(mRedirectMap.values()[i] == md5) //ignore when redirect processing
        {
            return md5;
        }
    }

    mProcessingRq.insert(md5, true);

    QNetworkRequest rq;
    QSslConfiguration config = rq.sslConfiguration();
    config.setPeerVerifyMode(QSslSocket::VerifyNone);
    config.setProtocol(QSsl::TlsV1SslV3);
    rq.setSslConfiguration(config);

    rq.setUrl(QUrl(url));
    QNetworkReply* rp = mNetAccessManager->post(rq, data);
    rp->setProperty("postMD5", md5);
    rp->setProperty("url", url);
    rp->setProperty("data", data);

    connect(rp, &QNetworkReply::finished        , this, &CHttpSupport::onHttpPostRspFinished);
    connect(rp, &QNetworkReply::downloadProgress, this, &CHttpSupport::onHttpPostRspProgress);

    return md5;
}

这是一个单例类,通过方法httpGet 和 httpPost可以发送http请求, 当收到请求的时候会通过对应的信号返回结果。

如果请求出错则数据是空的。

使用示例:

int main(int argc, char *argv[])

{

QObject::connect(CHttpSupport::instance(), &CHttpSupport::httpGetRspReady, [](QString url, QByteArray d){
        if(url == "http://vip.5211game.com/")
        {
            qDebug() << "GET";
            qDebug() << d;
        }
    });    

CHttpSupport::instance()->httpGet("http://vip.5211game.com/");
return 0;

}

 

运行结果:

处理成功,得到网页数据,并且这个地址重定向为https://vip.5211game.com/

在这种情况下http://vip.5211game.com/请求的结果返回信号的url为http://vip.5211game.com/ 而data为https://vip.5211game.com/的数据。

(PS:最新版本的Qt已经自动处理重定向了。)

用这个类下载一些小图标,小配置文件什么的很方便。

欢迎大家进行交流和改进。

 

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值