Qt http(s)同步请求测试(restfull中常用的get/post/put/delete、文件上传/下载)

前言:

说本次是测试,还不如说是总结,

本次测试的是一些常见的http请求,采用同步的方式实现

一、测试同步get请求

实现代码如下

/*!
 * \brief Tool::waitGet 同步get请求 返回json对象
 * \param url 请求的url
 * \param para 请求的参数
 * \param responseJsonObject 返回的json对象
 * \param errorString 错误提示串
 * \return
 */
bool Tool::waitGet(const QUrl &url, const QVariantMap &para, QJsonObject &responseJsonObject, QString &errorString)
{

    QNetworkRequest req;

    QUrlQuery qry(url.query());
    QMapIterator<QString, QVariant> i(para);
    while (i.hasNext()) {
        i.next();
        qry.addQueryItem(i.key(), i.value().toString());
    }

    QUrl finalUrl(url);
    finalUrl.setQuery(qry);
    req.setUrl(finalUrl);

 首先实例化QNetworkRequest,将传入参数作为url的查询参数

如https://localhost:3001/api/v1/users

加入参数后可能变成https://localhost:3001/api/v1/users?arg1=val1&arg2=val2

    QNetworkAccessManager netam;
    netam.setTransferTimeout(10000);
    QNetworkReply *reply = netam.get(req);

    QEventLoop eventLoop;
    connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
    eventLoop.exec();

 setTransferTimeout()设置超时时间,需要Qt5.15及以上版本才有,若使用较低版本,需要自己设置一个定时器实现(不明白官方,这么简单的功能,不早点实现)

然后创建一个事件循环,直到数据返回时,再继续向下执行

    if (reply->error() != QNetworkReply::NoError) {
        errorString = tr("Get请求异常") + reply->errorString();
        reply->deleteLater();
        return false;
    }

 检查返回结果是否正常

    QJsonParseError jsonParseError;
    QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &jsonParseError);
    reply->deleteLater();

    if (jsonParseError.error != QJsonParseError::NoError) {
        qWarning() << "Failed to parse text message as JSON object."
                 << "Error is:" << jsonParseError.errorString();
        errorString = QString("Response Data ERROR: %1").arg(jsonParseError.errorString());
        return false;
    } else if (!jsonDoc.isObject()) {
        qWarning() << "Received JSON message that is not an object";
        errorString = tr("返回JSON数据无法解析!");
        return false;
    }
    responseJsonObject = jsonDoc.object();

    return true;
}

 若返回正常,将返回数据作为json串进行处理,并返回

二、测试同步get文件下载

 实现代码如下

/*!
 * \brief Tool::waitGet  同步get请求 下载文件
 * \param url 请求的文件url
 * \param localFilePath 文件下载目录,若不指定,下载到系统下载目录
 * \param localFileName 传入时,只是文件名;若下载成功,返回文件全目录
 * \param errorString
 * \return
 */
bool Tool::waitGet(const QUrl &url, QString &localFilePath,
                   QString &localFileName, QString &errorString)
{

    QNetworkRequest req;

    req.setUrl(url);
    QNetworkAccessManager netam;
    netam.setTransferTimeout(10000);
    QNetworkReply *reply = netam.get(req);
    connect(&netam, &QNetworkAccessManager::sslErrors, &netam,
        [](QNetworkReply *reply, const QList<QSslError> &/*errors*/) {
                 reply->ignoreSslErrors(); });

    QEventLoop eventLoop;
    connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);

    eventLoop.exec();

 首先实例化QNetworkRequest,

 setTransferTimeout()设置超时时间,需要Qt5.15及以上版本才有,若使用较低版本,需要自己设置一个定时器实现(不明白官方,这么简单的功能,不早点实现)

然后创建一个事件循环,直到数据返回时,再继续向下执行

    if (reply->error() != QNetworkReply::NoError) {
        errorString = tr("Get请求异常") + reply->errorString();
        reply->deleteLater();
        return false;
    }

 检查返回结果是否正常

    QFileInfo fileInfo= url.path();
    QString filePath;
    if(localFilePath.isEmpty()){ //没有指定文件存放路径 ,默认存放在系统下载目录
        filePath = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);;
         QDir dir = QDir();
         if(!dir.exists(filePath)){
             dir.mkpath(filePath);
         }
    }else{
       filePath = localFilePath;
       QDir dir = QDir();
       if(!dir.exists(filePath)){
           dir.mkpath(filePath);
       }
    }

    QString fileUrl;

    if(localFileName.isEmpty()){ //没有指定更改文件名,使用默认文件名
        fileUrl = filePath + QLatin1String("/") + fileInfo.fileName();
    }else{
        fileUrl = filePath + QLatin1String("/") + localFileName;
    }

 若是指定了文件下载目录,就下载到指定目录中;若未指定,就下载到系统下载目录中

若指定了文件名,就使用指定文件名;若未指定文件名,从url中获取 

    QFile file = QFile(fileUrl);
    bool ret = file.open(QIODevice::WriteOnly|QIODevice::Truncate);    //创建文件
    if(!ret){
        errorString = tr("文件打开失败!%1").arg(file.errorString());
        return false;

    }
    QByteArray ba = reply->readAll();

    reply->deleteLater();
    file.write(ba);
    file.close();
       qDebug()<<"文件数据写入成功,写入的文件名 " + fileUrl;

    localFileName = fileUrl;

    return true;
}

 将所有的数据直接写入文件中

 若是文件太大,不建议使用同步下载,可能会卡住太长时间的

三、测试同步post请求

实现代码如下

/*!
 * \brief Tool::waitPost 同步post请求
 * \param url 请求的url
 * \param requestJsonObject 请求的post对象
 * \param responseJsonObject 返回的json对象
 * \param errorString 错误信息
 * \return
 */
bool Tool::waitPost(const QUrl &url, const QJsonObject &requestJsonObject, QJsonObject &responseJsonObject, QString &errorString)
{

    QNetworkRequest req;

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

 首先实例化QNetworkRequest,

请求的头要设置正确,否则很多服务器无法正常处理

    QNetworkAccessManager netam;
    netam.setTransferTimeout(10000);

    QNetworkReply *reply = netam.post(req,         QJsonDocument(requestJsonObject).toJson(QJsonDocument::Compact));

// 阻塞,等待请求完成
    QEventLoop eventLoop;
    connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
    eventLoop.exec();

 setTransferTimeout()设置超时时间,需要Qt5.15及以上版本才有,若使用较低版本,需要自己设置一个定时器实现(不明白官方,这么简单的功能,不早点实现)

然后创建一个事件循环,直到数据返回时,再继续向下执行

    if (reply->error() != QNetworkReply::NoError) {
        errorString = tr("POST请求异常") + reply->errorString();
        reply->deleteLater();
        return false;
    }

 检查返回结果是否正常

    QJsonParseError jsonParseError;
    QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &jsonParseError);
    reply->deleteLater();

    if (jsonParseError.error != QJsonParseError::NoError) {
        qWarning() << "Failed to parse text message as JSON object."
                 << "Error is:" << jsonParseError.errorString();
        errorString = QString("Response Data ERROR: %1").arg(jsonParseError.errorString());
        return false;
    } else if (!jsonDoc.isObject()) {
        qWarning() << "Received JSON message that is not an object";
        errorString = tr("返回JSON数据无法解析!");
        return false;
    }
    responseJsonObject = jsonDoc.object();

    return true;
}

 若返回正常,将返回数据作为json串进行处理,并返回

四、测试同步post 通过表单实现文件上传

实现代码如下

/*!
 * \brief Tool::waitPost
 * \param url 请求的文件url
 * \param fileName 要上传的文件
 * \param responseJsonObject 返回的json对象
 * \param errorString 错误信息
 * \return
 */
bool Tool::waitPost(const QUrl &url, const QString &fileName, QJsonObject &responseJsonObject, QString &errorString)
{

    QFileInfo info(fileName);
    if(!info.isFile())
    {
        errorString = tr("文件路径异常");
        return false;
    }

先确定下,文件是有效的

//设置multiPart
    QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
    QHttpPart filePart;
    QString header=QString("form-data; name=\"file\";filename=\"%1\"").arg(info.fileName());
    filePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(header));
    QFile *file = new QFile(fileName);
    file->open(QIODevice::ReadOnly);
    filePart.setBodyDevice(file);
    file->setParent(multiPart);
    // we cannot delete the file now, so delete it with the multiPart
    multiPart->append(filePart);

自定义的头部,一定要写对,要影响到服务器的解析;

若无法正常上传文件,可以去服务端看下,处理的参数是否正确 

    QNetworkRequest req;
    req.setUrl(url);
    
    QNetworkAccessManager netam;
    netam.setTransferTimeout(10000);

    QNetworkReply *reply = netam.post(req,         QJsonDocument(requestJsonObject).toJson(QJsonDocument::Compact));

// 阻塞,等待请求完成
    QEventLoop eventLoop;
    connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
    eventLoop.exec();

 setTransferTimeout()设置超时时间,需要Qt5.15及以上版本才有,若使用较低版本,需要自己设置一个定时器实现(不明白官方,这么简单的功能,不早点实现)

然后创建一个事件循环,直到数据返回时,再继续向下执行

    if (reply->error() != QNetworkReply::NoError) {
        errorString = tr("POST请求异常") + reply->errorString();
        reply->deleteLater();
        return false;
    }

 检查返回结果是否正常

    QJsonParseError jsonParseError;
    QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &jsonParseError);
    reply->deleteLater();

    if (jsonParseError.error != QJsonParseError::NoError) {
        qWarning() << "Failed to parse text message as JSON object."
                 << "Error is:" << jsonParseError.errorString();
        errorString = QString("Response Data ERROR: %1").arg(jsonParseError.errorString());
        return false;
    } else if (!jsonDoc.isObject()) {
        qWarning() << "Received JSON message that is not an object";
        errorString = tr("返回JSON数据无法解析!");
        return false;
    }
    responseJsonObject = jsonDoc.object();

    return true;
}

 若返回正常,将返回数据作为json串进行处理,并返回

请求url中,仍然可以放入查询参数的,方便传入一些参数

五、测试同步put请求

很多服务器已经不支持处理put请求了,需要先确定下服务端是否支持

客户端的实现基本与post方法相同,实现代码如下

/*!
 * \brief Tool::waitPut 同步put请求
 * \param url 请求的url
 * \param requestJsonObject 请求的post对象
 * \param responseJsonObject 返回的json对象
 * \param errorString 错误信息
 * \return
 */
bool Tool::waitPut(const QUrl &url, const QJsonObject &requestJsonObject, QJsonObject &responseJsonObject, QString &errorString)
{

    QNetworkRequest req;

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

 首先实例化QNetworkRequest,

请求的头要设置正确,否则很多服务器无法正常处理

    QNetworkAccessManager netam;
    netam.setTransferTimeout(10000);

    QNetworkReply *reply = netam.put(req,         QJsonDocument(requestJsonObject).toJson(QJsonDocument::Compact));

// 阻塞,等待请求完成
    QEventLoop eventLoop;
    connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
    eventLoop.exec();

 setTransferTimeout()设置超时时间,需要Qt5.15及以上版本才有,若使用较低版本,需要自己设置一个定时器实现(不明白官方,这么简单的功能,不早点实现)

然后创建一个事件循环,直到数据返回时,再继续向下执行

    if (reply->error() != QNetworkReply::NoError) {
        errorString = tr("PUT请求异常") + reply->errorString();
        reply->deleteLater();
        return false;
    }

 检查返回结果是否正常

    QJsonParseError jsonParseError;
    QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &jsonParseError);
    reply->deleteLater();

    if (jsonParseError.error != QJsonParseError::NoError) {
        qWarning() << "Failed to parse text message as JSON object."
                 << "Error is:" << jsonParseError.errorString();
        errorString = QString("Response Data ERROR: %1").arg(jsonParseError.errorString());
        return false;
    } else if (!jsonDoc.isObject()) {
        qWarning() << "Received JSON message that is not an object";
        errorString = tr("返回JSON数据无法解析!");
        return false;
    }
    responseJsonObject = jsonDoc.object();

    return true;
}

 若返回正常,将返回数据作为json串进行处理,并返回

六、测试同步delete请求

很多服务器已经不支持处理delete请求了,需要先确定下服务端是否支持

客户端的实现基本与get方法相同,实现代码如下

/*!
 * \brief Tool::waitDelete 同步delete请求 返回json对象
 * \param url 请求的url
 * \param para 请求的参数
 * \param responseJsonObject 返回的json对象
 * \param errorString 错误提示串
 * \return
 */
bool Tool::waitDelete(const QUrl &url, const QVariantMap &para, QJsonObject &responseJsonObject, QString &errorString)
{

    QNetworkRequest req;

    QUrlQuery qry(url.query());
    QMapIterator<QString, QVariant> i(para);
    while (i.hasNext()) {
        i.next();
        qry.addQueryItem(i.key(), i.value().toString());
    }

    QUrl finalUrl(url);
    finalUrl.setQuery(qry);
    req.setUrl(finalUrl);

 首先实例化QNetworkRequest,将传入参数作为url的查询参数

如https://localhost:3001/api/v1/users

加入参数后可能变成https://localhost:3001/api/v1/users?arg1=val1&arg2=val2

    QNetworkAccessManager netam;
    netam.setTransferTimeout(10000);
    QNetworkReply *reply = netam.get(req);

    QEventLoop eventLoop;
    connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
    eventLoop.exec();

 setTransferTimeout()设置超时时间,需要Qt5.15及以上版本才有,若使用较低版本,需要自己设置一个定时器实现(不明白官方,这么简单的功能,不早点实现)

然后创建一个事件循环,直到数据返回时,再继续向下执行

    if (reply->error() != QNetworkReply::NoError) {
        errorString = tr("delete请求异常") + reply->errorString();
        reply->deleteLater();
        return false;
    }

 检查返回结果是否正常

    QJsonParseError jsonParseError;
    QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &jsonParseError);
    reply->deleteLater();

    if (jsonParseError.error != QJsonParseError::NoError) {
        qWarning() << "Failed to parse text message as JSON object."
                 << "Error is:" << jsonParseError.errorString();
        errorString = QString("Response Data ERROR: %1").arg(jsonParseError.errorString());
        return false;
    } else if (!jsonDoc.isObject()) {
        qWarning() << "Received JSON message that is not an object";
        errorString = tr("返回JSON数据无法解析!");
        return false;
    }
    responseJsonObject = jsonDoc.object();

    return true;
}

 若返回正常,将返回数据作为json串进行处理,并返回

七、增加SSL支持

以上同步操作的实现,都是http请求,现在更多的是https请求,需要在请求对象中,加入如下配置

QNetworkRequest request;
...
#if QT_CONFIG(ssl)
    QSslConfiguration ssl;
    ssl.setPeerVerifyMode(QSslSocket::VerifyNone);
    ssl.setProtocol(QSsl::AnyProtocol);
    req.setSslConfiguration(ssl);
#endif

 以上是单向证书需要配置的参数,笔者不建议设置全部协议,建议具体设置使用的协议

 只设置这些还不够,还需要忽略ssl错误才行

#if QT_CONFIG(ssl)
    connect(&netam, &QNetworkAccessManager::sslErrors, &netam,
        [](QNetworkReply *reply, const QList<QSslError> &/*errors*/) {
                 reply->ignoreSslErrors(); });
#endif

若是要设置双向证书,添加如下代码

QNetworkRequest request;
...
#if QT_CONFIG(ssl)
    QSslConfiguration ssl;
    QList<QSslCertificate> certs = QSslCertificate::fromPath("C:\\certificate.crt");
    ssl.setCaCertificates(certs);

    request.setSslConfiguration(ssl);
#endif

示例代码下载

后记:

Qt本身的http是异步的,记得一个QNetworkAccessManager会创建6个连接,所以同一个对象,不要同时超过6个请求

笔者建议,若非必要,还是使用异步的方式通信,不建议使用同步的方式

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

꧁白杨树下꧂

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

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

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

打赏作者

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

抵扣说明:

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

余额充值