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

总结

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

相关推荐
弘毅_Hao2 小时前
Qt clicked()、clicked(bool)、toggled(bool)信号的区别和联系
qt·按钮点击信号
机器视觉知识推荐、就业指导2 小时前
Qt/C++ TCP调试助手V1.1 新增图像传输与接收功能(附发布版下载链接)
c++·qt·tcp/ip
痛&快乐着3 小时前
python-在PyCharm中使用PyQt5
python·qt·pycharm
生信宝典5 小时前
ROC和AUC也不是评估机器学习性能的金标准
人工智能·qt·机器学习
机器视觉知识推荐、就业指导12 小时前
Qt/C++事件过滤器与控件响应重写的使用、场景的不同
开发语言·数据库·c++·qt
doll ~CJ15 小时前
可视化工具箱-Visualization Toolkit(VTK)
qt·vtk_9.1.0·release_x64
霍霍哈嗨16 小时前
【QT基础】创建项目&项目代码解释
开发语言·qt
Eoneanyna18 小时前
QT设置git仓库
开发语言·git·qt
Langneer1 天前
Qt 状态机编程,双层状态机,实现暂停恢复
开发语言·qt
三玖诶1 天前
如何在 Qt 的 QListWidget 中为某一行添加点击事件
开发语言·qt