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

总结

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

相关推荐
用户805533698031 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner1 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz6 天前
QML Hello World 入门示例
qt
xcyxiner9 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner10 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner10 天前
DicomViewer (添加模型类)3
qt
xcyxiner11 天前
DicomViewer (目录调整) 2
qt
xcyxiner11 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
桥田智能13 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
森G13 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt