【QT常用技术讲解】发送POST包(两种方式:阻塞方式及非阻塞方式)

news2024/12/24 10:17:46

前言

        http/https(应用层)协议是广泛使用的网络通信协议。在很多与第三方API对接的场景中,通常是通过http/https协议完成,比如API对接时,通常要通过POST包获取access_token进行鉴权,然后再进行数据交互(本篇也包含有对接收数据的json数据解析代码)。

        本篇以百度AI的API接口的access_token鉴权为例,通过QT特性QNetworkAccessManager实现两种方式的POST包方式:阻塞方式和非阻塞方式。

功能讲解

阻塞方式

        QT开发的工具,通常没有高并发的网络通信服务需求,类似原生socket一样,send完数据之后就(阻塞方式)recv数据,这是非常普遍的调用方式,以下展示调用百度AI的API鉴权接口的过程。

//头文件networkmanager.h
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QEventLoop>
#include <QUrl>
#include <QUrlQuery>
#include <QJsonDocument>
#include <QJsonObject>
#include <QObject>
#include <QDebug>
#define API_KEY "GU1GeuGXNDhG48Z2aMYE2rD1"
#define SECRET_KEY "NxrnIMZ7hi8vfIT734SiLhmwCpStEN8K"

class NetworkManager : public QObject
{
    Q_OBJECT
public:
    explicit NetworkManager(QObject *parent = nullptr);
    QByteArray  block_post_data(const QNetworkRequest& request,const QUrlQuery& postData);
    QString get_access_token(const QString& client_id,const QString& client_secret) ;
};


//cpp文件networkmanager.cpp
#include "networkmanager.h"

NetworkManager::NetworkManager(QObject *parent) : QObject(parent)
{

}

QByteArray NetworkManager::block_post_data(const QNetworkRequest& request,const QUrlQuery& postData){
    //QString resstr;
    QByteArray responseData;
    // 创建网络访问管理器
    QNetworkAccessManager block_manager;//这里不要用QNetworkAccessManager *block_manager的方式
    // 发送POST请求
    QNetworkReply* reply = block_manager.post(request, postData.toString(QUrl::FullyEncoded).toUtf8());

    // 创建一个事件循环来阻塞当前线程
    QEventLoop loop;
    QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    // 阻塞当前线程直到网络请求完成
    loop.exec();
    // 检查请求结果
    if (reply->error() == QNetworkReply::NoError) {
        // 请求成功,处理返回的数据
        /*QByteArray */responseData = reply->readAll();
        //resstr = QString::fromUtf8(responseData);
        //qDebug() << __LINE__ <<"Response:" << resstr;
    } else {
        // 请求失败,处理错误
        qDebug() << "Error:" << reply->errorString();
        responseData="";
    }
    // 清理
    reply->deleteLater();
    return responseData;
}


QString NetworkManager::get_access_token(const QString& client_id,const QString& client_secret) {
    QString access_token;
    QUrl url("https://aip.baidubce.com/oauth/2.0/token");
    QNetworkRequest request(url);
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
    request.setRawHeader("Accept", "application/json");

    // 创建 POST 数据
    QUrlQuery postData;
    postData.addQueryItem("grant_type", "client_credentials");
    postData.addQueryItem("client_id", client_id);
    postData.addQueryItem("client_secret", client_secret);

    //发送Post包(通过阻塞方式获取返回结果)
    QByteArray jsonData=block_post_data(request,postData);
    // 解析 JSON 数据
    QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData);
    if (jsonDoc.isNull()) {
        qDebug() << "Failed to create JSON doc.";
        return "";
    }
    // 检查 JSON 文档类型
    if (jsonDoc.isObject()) {
        QJsonObject jsonObj = jsonDoc.object();
        //qDebug() << "JSON Object:" << jsonObj;
        // 访问 JSON 对象中的数据
        if (jsonObj.contains("access_token")) {
            access_token = jsonObj["access_token"].toString();
            qDebug() << "access_token:" << access_token;
        }
    } else {
        qDebug() << "JSON is not an object.";
    }
    return access_token;
}


//主函数文件main.cpp
#include "networkmanager.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    NetworkManager networkManager;
    QString access_token=networkManager.get_access_token(API_KEY,SECRET_KEY);
    return a.exec();
}

以上代码中,调用QNetworkAccessManager的post之后,通过循环事件来阻塞线程,直到获取到结果(QNetworkReply::finished)之后,才退出事件循环(QEventLoop::quit)。

    // 创建一个事件循环来阻塞当前线程
    QEventLoop loop;
    QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    // 阻塞当前线程直到网络请求完成
    loop.exec();

除此之外,源代码还包含了json解析部分,因为只有一个层级,直接获取access_token字段的内容即可。

// 解析 JSON 数据
    QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData);
    if (jsonDoc.isNull()) {
        qDebug() << "Failed to create JSON doc.";
        return "";
    }
    // 检查 JSON 文档类型
    if (jsonDoc.isObject()) {
        QJsonObject jsonObj = jsonDoc.object();
        //qDebug() << "JSON Object:" << jsonObj;
        // 访问 JSON 对象中的数据
        if (jsonObj.contains("access_token")) {//-----json格式中最外层的access_token字段
            access_token = jsonObj["access_token"].toString();
            qDebug() << "access_token:" << access_token;
        }
    } else {
        qDebug() << "JSON is not an object.";
    }

非阻塞方式

        在设计时,如果异步处理更加符合框架的处理性能需求时,比如鉴权完成之后,批量调用百度AI的OCR接口时,批量的组装并发送POST包,然后异步的接收数据之后,保存到本地(或者是抽取关键数据)的场景时,就得用异步的方式,以下只是展示调用百度AI的API鉴权接口来贴源代码。

//头文件networkmanager.h
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QByteArray>
#include <QUrlQuery>
#include <QJsonDocument>
#include <QJsonObject>
#include <QObject>
#include <QDebug>

#define API_KEY "GU1GeuGXNDhG48Z2aMYE2rD1"
#define SECRET_KEY "NxrnIMZ7hi8vfIT734SiLhmwCpStEN8K"

class NetworkManager : public QObject
{
    Q_OBJECT
public:
    explicit NetworkManager(QObject *parent = nullptr);
    void get_access_token(const QString& client_id,const QString& client_secret) ;
private slots:
    void onFinished(QNetworkReply *reply);

private:
    QNetworkAccessManager *manager;
};

--------------------------------------------------------------------------

//cpp文件networkmanager.cpp
#include "networkmanager.h"

NetworkManager::NetworkManager(QObject *parent) : QObject(parent)
{
    manager = new QNetworkAccessManager(this);
    connect(manager, &QNetworkAccessManager::finished, this, &NetworkManager::onFinished);//接收数据的槽函数
}


void NetworkManager::get_access_token(const QString& client_id,const QString& client_secret) {
    QUrl url("https://aip.baidubce.com/oauth/2.0/token");
    QNetworkRequest request(url);
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
    request.setRawHeader("Accept", "application/json");

    // 创建 POST 数据
    QUrlQuery postData;
    postData.addQueryItem("grant_type", "client_credentials");
    postData.addQueryItem("client_id", client_id);
    postData.addQueryItem("client_secret", client_secret);

    // 发送 POST 请求
    //manager->post(request, jsonData);
    // 发送 POST 请求
    manager->post(request, postData.toString(QUrl::FullyEncoded).toUtf8());

}


void NetworkManager::onFinished(QNetworkReply *reply) {
    if (reply->error() == QNetworkReply::NoError) {
        QByteArray responseData = reply->readAll();
        qDebug() << "Response:" << responseData;
    } else {
        qDebug() << "Error:" << reply->errorString();
    }
    reply->deleteLater();
}


//主函数main.cpp
#include <QApplication>
#include "networkmanager.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    NetworkManager networkManager;
    networkManager.get_access_token(API_KEY,SECRET_KEY);

    return a.exec();
}

源码中通过信号和槽机制,统一获取并处理Post的返回结果。

//通过信号和槽机制,统一获取并处理Post的返回结果
manager = new QNetworkAccessManager(this);
connect(manager, &QNetworkAccessManager::finished, this, &NetworkManager::onFinished);

void NetworkManager::onFinished(QNetworkReply *reply) {
    if (reply->error() == QNetworkReply::NoError) {
        QByteArray responseData = reply->readAll();
        qDebug() << "Response:" << responseData;
    } else {
        qDebug() << "Error:" << reply->errorString();
    }
    reply->deleteLater();
}

片尾

        因为百度API是https调用的,QT环境需要专门匹配的SSL版本来支持,如果没有对应的动态文件,编译时会如下报错:

以下提供一个传送门:

解决qt.network.ssl 和 OpenSSL 1.1.1g Win64版本EXE下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2264665.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【电商搜索】文档的信息论生成聚类

【电商搜索】文档的信息论生成聚类 目录 文章目录 【电商搜索】文档的信息论生成聚类目录文章信息概览研究背景技术挑战如何破局技术应用主要相关工作与参考文献后续优化方向 后记 文章信息 https://arxiv.org/pdf/2412.13534 概览 本文提出了一种基于信息论的生成聚类&#…

【数据结构与算法】排序算法(下)——计数排序与排序总结

写在前面 书接上文&#xff1a;【数据结构与算法】排序算法(中)——交换排序之快速排序 文章主要讲解计数排序的细节与分析源码。之后进行四大排序的总结。 文章目录 写在前面一、计数排序(非比较排序)代码的实现&#xff1a; 二、排序总结 2.1、稳定性 3.2、排序算法复杂度及…

Unity全局雾效

1、全局雾效是什么 全局雾效&#xff08;Global Fog&#xff09;是一种视觉效果&#xff0c;用于在3D场景中模拟大气中的雾气对远处物体的遮挡 它通过在场景中加入雾的效果&#xff0c;使得距离摄像机较远的物体看起来逐渐被雾气覆盖&#xff0c;从而创造出一种朦胧、模糊的视…

Kafka Streams 在监控场景的应用与实践

作者&#xff1a;来自 vivo 互联网服务器团队- Pang Haiyun 介绍 Kafka Streams 的原理架构&#xff0c;常见配置以及在监控场景的应用。 一、背景 在当今大数据时代&#xff0c;实时数据处理变得越来越重要&#xff0c;而监控数据的实时性和可靠性是监控能力建设最重要的一环…

数据分析思维(五):分析方法——假设检验分析方法

数据分析并非只是简单的数据分析工具三板斧——Excel、SQL、Python&#xff0c;更重要的是数据分析思维。没有数据分析思维和业务知识&#xff0c;就算拿到一堆数据&#xff0c;也不知道如何下手。 推荐书本《数据分析思维——分析方法和业务知识》&#xff0c;本文内容就是提取…

解读DiffusionNER: Boundary Diffusion for Named Entity Recognition

content 摘要1. 图1图21. 上方&#xff1a;扩散过程与实体边界2. 下方&#xff1a;网络结构&#xff08;Sentence Encoder Entity Decoder&#xff09;3. 关键思想小结 摘要 主要内容分为四个部分&#xff1a; 模型定位与基本原理&#xff1a; 提出了DiffusionNER模型将命名…

【QSS样式表 - ⑥】:QPushButton控件样式

文章目录 QPushBUtton控件样式QSS示例 QPushBUtton控件样式 常用子控件 常用伪状态 QSS示例 代码&#xff1a; QPushButton {background-color: #99B5D1;color: white;font-weigth: bold;border-radius: 20px; }QPushButton:hover {background-color: red; }QPushButton:p…

数字经济下的 AR 眼镜

目录 1. &#x1f4c2; AR 眼镜发展历史 1.1 AR 眼镜相关概念 1.2 市面主流 XR 眼镜 1.3 AR 眼镜大事记 1.4 国内外 XR 眼镜 1.5 国内 AR 眼镜四小龙 2. &#x1f531; 关键技术 2.1 AR 眼镜近眼显示原理 2.2 AR 眼镜关键技术 2.3 AR 眼镜技术难点 3. &#x1f4a…

smb和nfs双栈协议共享目录

1 简介 NFS和SAMBA协议都是文件共享&#xff0c;Linux客户端常用于NFS协议访问远程共享目录&#xff0c;Windows客户端常用于SAMBA协议访问远程共享目录。 2 环境 合计使用三台服务器&#xff0c;服务器都位于同一个子网&#xff08;10.0.0.0/19&#xff09;、同一个安全组…

Day13 用Excel表体验梯度下降法

Day13 用Excel表体验梯度下降法 用所学公式创建Excel表 用Excel表体验梯度下降法 详见本Day文章顶部附带资源里的Excel表《梯度下降法》&#xff0c;可以对照表里的单元格公式进行理解&#xff0c;还可以多尝试几次不同的学习率 η \eta η来感受&#xff0c;只需要更改学习率…

Python获取系统负载并打印折线图

#! /opt/py36/bin/python import psutil import matplotlib.pyplot as plt import time# 创建一个空列表&#xff0c;用于存储负载数据 load_data []# 循环收集负载数据 while True:# 获取当前系统负载load_avg psutil.getloadavg()# 将平均负载添加到load_data列表中load_da…

RCE 命令执行漏洞 过滤模式 基本的过滤问题 联合ctf题目进行实践

前言 知道RCE 命令执行分为 代码执行 和 命令执行 原理 &#xff1a; 就是用户的输入被当做命令或者代码执行了 从而造成了危害 代码执行 除了eval php代码执行漏洞的函数还有 eval()、a ssert()、 preg_replace()、 create_function()、 array_map()、 call_user_func(…

Leetcode打卡:考场就坐

执行结果&#xff1a;通过 题目&#xff1a; 855 考场就坐 在考场里&#xff0c;有 n 个座位排成一行&#xff0c;编号为 0 到 n - 1。 当学生进入考场后&#xff0c;他必须坐在离最近的人最远的座位上。如果有多个这样的座位&#xff0c;他会坐在编号最小的座位上。(另外&am…

数据结构(哈希表(上)纯概念版)

前言 在软件开发和计算机科学中&#xff0c;数据结构的选择直接影响到程序的性能和效率。不同的数据结构适用于不同的场景&#xff0c;合理地选择合适的数据结构是高效编程的关键之一。哈希表&#xff08;哈希表&#xff08;Hash Table&#xff09;作为一种高效的键值对存储结…

【机器学习与数据挖掘实战】案例06:基于Apriori算法的餐饮企业菜品关联分析

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈机器学习与数据挖掘实战 ⌋ ⌋ ⌋ 机器学习是人工智能的一个分支,专注于让计算机系统通过数据学习和改进。它利用统计和计算方法,使模型能够从数据中自动提取特征并做出预测或决策。数据挖掘则是从大型数据集中发现模式、关联…

深入解析 Spring WebFlux:原理与应用

优质博文&#xff1a;IT-BLOG-CN WebFlux 是 Spring Framework 5 引入的一种响应式编程框架&#xff0c;和Spring MVC同级&#xff0c;旨在处理高并发和低延迟的非阻塞应用。这是一个支持反应式编程模型的新Web框架体系。 顺便一提&#xff0c;Spring Cloud Gateway在实现上是…

C语言基础——指针(4)

一&#xff0e; 字符指针变量 字符指针变量的使用和整型指针变量的使用方法相似&#xff0c;以下是其基本使用方法的例子&#xff1a; &#xff08;1&#xff09;字符指针变量还有一种使用方法&#xff1a; const char* p "abcd" 需…

『 Linux 』高级IO (一)

文章目录 内容回顾及铺垫五种IO模型不同类型IO的区别非阻塞IOfcntl( ) 多路转接 - select( )select( ) 的基本使用 - SelectServer服务器 内容回顾及铺垫 在博客『 Linux 』基础IO/文件IO (万字)中介绍了对IO的认识; IO实际上为Input/Output,输入输出; 以网络协议栈的视角来看,…

Spark-Streaming集成Kafka

Spark Streaming集成Kafka是生产上最多的方式&#xff0c;其中集成Kafka 0.10是较为简单的&#xff0c;即&#xff1a;Kafka分区和Spark分区之间是1:1的对应关系&#xff0c;以及对偏移量和元数据的访问。与高版本的Kafka Consumer API 集成时做了一些调整&#xff0c;下面我们…

「下载」智慧城市包括哪些方面:大数据公共服务平台、城市运行指挥中心、城市综合治理平台、城市体检综合运营平台解决方案

在当今信息化高速发展的时代&#xff0c;智慧城市已成为全球城市发展的新趋势。系列全面而创新的智慧城市解决方案&#xff0c;旨在助力城市实现智慧化转型&#xff0c;提升城市管理效率&#xff0c;增强市民生活质量。 智慧城市最新解决方案&#xff0c;标准规范顶层设计指南、…