Qt http

文章目录

  • 前言
    • [1. 定义的接口](#1. 定义的接口)
    • 2.connect信号槽
    • [3. get](#3. get)
    • [4. get 下载文件](#4. get 下载文件)
    • [5. post](#5. post)
  • 总结

前言

/*

1.请求报文:

请求报文是由客户端发送给服务器,用于请求特定资源或执行特定操作。它由以下几个部分组成:

请求行:描述了请求的方法、目标资源的路径和HTTP协议的版本,通常包含以下三个字段:

复制代码
        请求方法:指定了客户端希望服务器执行的操作,如GET、POST、PUT、DELETE等。
请求目标:表示客户端希望访问的资源路径,可以是绝对路径或相对路径。
    协议版本:指定所使用的HTTP协议的版本,如HTTP/1.1。
请求头:包含了关于请求的附加信息,格式为键值对。常见的请求头字段包括:

Host:指定请求的目标主机。
User-Agent:标识发送请求的客户端应用程序。
Content-Type:指定请求正文的类型。
请求正文(可选):包含客户端发送给服务器的数据,通常在使用POST等方法时使用。

2.响应报文:

响应报文是服务器对客户端请求的回应,包含了所请求资源的数据或执行结果。它由以下几个部分组成:

状态行:描述了响应的状态,包含以下三个字段:

复制代码
协议版本:指定所使用的HTTP协议的版本,如HTTP/1.1。
状态码:表示服务器对请求的处理结果,如200表示成功,404表示资源未找到。
状态信息:对状态码进行简短的解释说明。
响应头:包含了关于响应的附加信息,格式为键值对。常见的响应头字段包括:

Content-Type:指定响应正文的类型。
Content-Length:指定响应正文的长度。
Set-Cookie:在响应中设置Cookie。
响应正文:包含了服务器返回给客户端的数据,可以是HTML、JSON、文件等。

请求报文和响应报文的结构化文本格式使得客户端和服务器能够互相理解并进行有效的通信。
它们是HTTP通信的基础,用于传递请求和响应的相关信息

******************************************************
text/html 表示数据格式是 HTML
text/css 表示数据格式是 CSS
application/javascript 表示数据各式是 JavaScript
application/json 表示数据格式是 JSON
******************************************************

*/


1. 定义的接口

  1. public公共接口,用作单线程
  2. public slots公共槽函数,支持类对象调用,在哪个线程调用即在哪个线程运行
  3. signals 信号,通过调用信号的方式在其对应槽函数线程创建事件执行,用于多线程
cpp 复制代码
public:
    bool get(QString url, QString &data, int timeout = 20000);

    bool post(QString url, QString &data, QByteArray jsonData, int timeout = 20000);

    bool getDownload(QString url, QString filePath, int timeout = 20000);


signals:
    void sgnGet(QString url, int timeout = 20000);

    void sgnPost(QString url,QByteArray jsonData, int timeout = 20000);

    void sgnGetDownload(QString url, QString filePath, int timeout = 20000);

    void Progress(qint64, qint64);

    void finished(QString data, bool result);

public slots:
    void gets(QString url, int timeout = 20000);

    void posts(QString url,QByteArray jsonData, int timeout = 20000);

    void getDownloads(QString url, QString filePath, int timeout = 20000);

2.connect信号槽

cpp 复制代码
    connect(this, &Http::sgnGet, this, &Http::gets);
    connect(this, &Http::sgnGetDownload, this, &Http::getDownloads);
    connect(this, &Http::sgnPost, this, &Http::posts);

3. get

cpp 复制代码
//! 通过信号槽的方式调动
void Http::gets(QString url, int timeout)
{
    QString data = "";
    bool rt = this->get(url, data, timeout);
    emit finished(data, rt);
}
cpp 复制代码
//! get请求数据
bool Http::get(QString url, QString& data, int timeout)
{
    qDebug()<<"Http       QThread::currentThread() = "<<QThread::currentThread();
    int repeatSend = 0;
    // 三次请求失败结束请求数据
    while(!repeatGet(url, data, timeout))
    {
        if(++repeatSend >= 3) return false;
    }
    return true;
}
cpp 复制代码
//!
bool Http::repeatGet(QString& url, QString& data, int& timeout)
{
    // 建立事件循环
    QEventLoop loop;
    //设置发送请求所需的信息
    QNetworkRequest request;
    request.setUrl(QUrl(url));
    request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/x-www-form-urlencoded"));
    //管理网络请求和响应
    QNetworkAccessManager manager;
    connect(&manager, &QNetworkAccessManager::finished, &loop, &QEventLoop::quit);
    // 超时检测
    QTimer timer;
    timer.setSingleShot(true);
    connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
    // 处理网络请求的响应数据
    QNetworkReply* pReply = manager.get(request);
    connect(pReply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    connect(pReply, SIGNAL(error(QNetworkReply::NetworkError)), &loop, SLOT(quit()));
    // 超时检测定时器启动
    timer.start((timeout > 0) ? timeout : 2000);
    //执行事件循环,直到退出循环再执行后面代码
    loop.exec();

    //! 退出事件循环,判断定时器是否触发,触发即超时
    if(!timer.isActive())
    {
        pReply->deleteLater();
        return false;
    }

    //! 未超时停止定时器
    timer.stop();
    //
    QNetworkReply::NetworkError err = pReply->error();
    if(err != QNetworkReply::NoError)
    {
        // 检测状态码
        int statusCode  = pReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
        qDebug()<<"get error, statusCode = "<<statusCode;
        return false;
    }
    //
    data = QString::fromUtf8(pReply->readAll());
    pReply->deleteLater();
    return true;
}

执行代码:

cpp 复制代码
QString data = "";
qDebug()<<"----------------------------------";
qDebug()<< "MainWindow QThread::currentThread() = "<< QThread::currentThread();
qDebug()<<data.size();
data.clear();
qDebug()<<"--------------- 1 ----------------";
http->get(QString("http://www.baidu.com"),data, 2000);
qDebug()<<data.size();
data.clear();
qDebug()<<"--------------- 2 ----------------";
http->gets(QString("http://www.baidu.com"), 2000);
qDebug()<<data.size();
data.clear();
qDebug()<<"--------------- 3 ----------------";
emit http->sgnGet(QString("http://www.baidu.com"), 2000);
qDebug()<<data.size();
qDebug()<<"----------------------------------";
// 保存HTTP响应内容
// 组装保存的文件名 文件名格式: 路径/年_月_日 小时_分_秒 httpfile.html
QDateTime current_date_time =QDateTime::currentDateTime();
QString current_date =current_date_time.toString("yyyy_MM_dd hh_mm_ss");
QString filePath = ".";
QString fileName = filePath + '/' + current_date + " httpfile" + ".html";

QFile file(fileName);
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)){
    //qDebug() << "file open error!";
    return ;
}
QTextStream out(&file);
out.setCodec("UTF-8");
out<<data;
file.close();
data.clear();

通过信号槽是多线程且异步的

4. get 下载文件

cpp 复制代码
void Http::getDownloads(QString url, QString filePath, int timeout)
{
    bool rt = this->getDownload(url, filePath, timeout);
    emit finished(filePath, rt);
}
cpp 复制代码
bool Http::getDownload(QString url, QString filePath, int timeout)
{
    qDebug()<<"Http        QThread::currentThread() = "<<QThread::currentThread();
    int repeatSend = 0;
    //
    while(!repeatGetDownload(url, filePath, timeout))
    {
        if(++repeatSend >= 3) return false;
    }
    return true;
}
cpp 复制代码
bool Http::repeatGetDownload(QString& url, const QString& filePath, const int& timeout)
{
    if(!pFile.isOpen()) pFile.setFileName(filePath);
    //
    QEventLoop loop;
    //
    QNetworkRequest request;
    request.setUrl(QUrl(url));
    //
    QNetworkAccessManager manager;
    connect(&manager, &QNetworkAccessManager::finished, &loop, &QEventLoop::quit);
    //
    QTimer timer;
    timer.setSingleShot(true);
    connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
    //
    QNetworkReply* pReply = manager.get(request);
    connect(pReply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    connect(pReply, SIGNAL(error(QNetworkReply::NetworkError)), &loop, SLOT(quit()));
    connect(pReply, &QNetworkReply::readyRead, &loop, &QEventLoop::quit);
    //
    timer.start((timeout > 0) ? timeout : 20000);
    loop.exec(QEventLoop::ExcludeSocketNotifiers);
    disconnect(pReply, &QNetworkReply::readyRead, &loop, &QEventLoop::quit);

    //! 超时
    if(!timer.isActive())
    {
        pReply->deleteLater();
        return false;
    }else{
        timer.stop();
    }

    QNetworkReply::NetworkError err = pReply->error();
    if(err != QNetworkReply::NoError)
    {
        // 检测状态码
        int statusCode  = pReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
        qDebug()<<"get error, statusCode = "<<statusCode;

        //! 重定向
        const QVariant redirectionTarget = pReply->attribute(QNetworkRequest::RedirectionTargetAttribute);
        if(!redirectionTarget.isNull())
        {
            QUrl redirectedUrl = redirectionTarget.toUrl();
            url = redirectedUrl.toString();
        }

        return false;
    }

    connect(pReply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(LoadProgress(qint64,qint64)));
    connect(pReply, &QNetworkReply::readyRead, this, &Http::readSave);
    loop.exec();

    return true;
}
cpp 复制代码
void Http::readSave()
{
    QNetworkReply* pReply = (QNetworkReply*)sender();

    if(!pFile.isOpen())
    {
        //! save file
        if(!pFile.open(QIODevice::WriteOnly))
        {
            qDebug() << pFile.errorString();
        }
    }
    pFile.write(pReply->readAll());
}
cpp 复制代码
void Http::LoadProgress(qint64 recved, qint64 total)
{
    QNetworkReply* pReply = (QNetworkReply*)sender();
    
    if(recved >= total)
    {
        pFile.close();
        pReply->deleteLater();
    }
}

执行代码

cpp 复制代码
QString url = "https://1.as.dl.wireshark.org/win64/Wireshark-win64-4.0.10.exe";
url = "https://enigmaprotector.com/assets/files/enigma_en_demo.exe";

qDebug()<<"----------------------------------";
qDebug()<< "MainWindow QThread::currentThread() = "<< QThread::currentThread();
qDebug()<<"--------------- 1 ----------------";
QString path = "./enigma1.exe";
//http->getDownload(url, path, 4000);
qDebug()<<"--------------- 2 ----------------";
path = "./enigma2.exe";
//http->getDownloads(url, path, 4000);
qDebug()<<"--------------- 3 ----------------";
path = "./enigma3.exe";
emit http->sgnGetDownload(url, path, 4000);
qDebug()<<"----------------------------------";

5. post

没测试过

cpp 复制代码
void Http::posts(QString url,QByteArray jsonData, int timeout)
{
    QString data;
    bool rt = this->post(url, data, jsonData, timeout);
    emit finished(data, rt);
}
cpp 复制代码
//!
bool Http::post(QString url, QString& data, QByteArray jsonData, int timeout)
{
    int repeatSend = 0;
    //
    while(!repeatPost(url, data, jsonData, timeout))
    {
        ++repeatSend;
        if(++repeatSend >= 3)
            return false;
    }
    return true;
}

//
bool Http::repeatPost(QString& url, QString& data, QByteArray& jsonData, int& timeout)
{
    //
    QEventLoop loop;
    //
    QNetworkRequest request;
    request.setUrl(QUrl(url));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "text/xml;charset=UTF-8");
    //
    QNetworkAccessManager manager;
    connect(&manager, &QNetworkAccessManager::finished, &loop, &QEventLoop::quit);
    //
    QTimer timer;
    timer.setSingleShot(true);
    connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
    //
    QNetworkReply* pReply = manager.post(request, jsonData);
    connect(pReply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    connect(pReply, SIGNAL(error(QNetworkReply::NetworkError)), &loop, SLOT(quit()));
    //
    timer.start((timeout > 0) ? timeout : 2000);
    loop.exec();

    //! 超时
    if(!timer.isActive())
    {
        pReply->deleteLater();
        return false;
    }

    //!
    timer.stop();
    //
    QNetworkReply::NetworkError err = pReply->error();
    if(err != QNetworkReply::NoError)
    {
        //! 检测状态码
        int statusCode  = pReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
        qDebug()<<"get error, statusCode = "<<statusCode;

        //! 重定向
        const QVariant redirectionTarget = pReply->attribute(QNetworkRequest::RedirectionTargetAttribute);
        if(!redirectionTarget.isNull())
        {
            QUrl redirectedUrl = redirectionTarget.toUrl();
            url = redirectedUrl.toString();
        }
        return false;
    }
    //!
    data = QString::fromUtf8(pReply->readAll());
    pReply->deleteLater();
    return true;
}

总结

学啥记啥,好记性不如烂笔头!

相关推荐
A.A呐7 小时前
【QT第三章】常用控件2
开发语言·qt
笨笨马甲7 小时前
Qt 实现三维坐标系的方法
开发语言·qt
谁动了我的代码?8 小时前
VNC中使用QT的GDB调试,触发断点时与界面窗口交互导致整个VNC冻结
开发语言·qt·svn
肖恭伟9 小时前
QtCreator Linux ubuntu24.04问题集合
linux·windows·qt
vegetablesssss10 小时前
QT国际化翻译
qt
困死,根本不会10 小时前
Qt Designer 基础操作学习笔记
开发语言·笔记·qt·学习·microsoft
喜欢喝果茶.10 小时前
Qt MQTT部署
开发语言·qt
浅碎时光80710 小时前
Qt 窗口 (菜单 工具栏 状态栏 浮动窗口 对话框)
qt
GIS阵地11 小时前
一场由Qt5 painter的drawRect引起的血雨腥风
开发语言·qt·gis·qgis
娇娇yyyyyy11 小时前
QT编程(8): qt自定义菜单项
qt·microsoft