当前位置:   article > 正文

QT之https通讯实例(百度API)_qt base64string.topercentencoding()

qt base64string.topercentencoding()

一、了解Http通讯

在使用qt做http通讯前,我们得先学习了解http。我们从以下几个方面来了解http。
  • 1

1.http方法

根据 HTTP 标准,HTTP 请求可以使用多种请求方法。
HTTP1.0 定义了三种请求方法: GET, POST 和 HEAD 方法。
HTTP1.1 新增了六种请求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法。

序号方法描述
1GET请求指定的页面信息,并返回实体主体。
2HEAD类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头
3POST向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和/或已有资源的修改。
4PUT从客户端向服务器传送的数据取代指定的文档的内容。
5DELETE请求服务器删除指定的页面。
6CONNECTHTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。
7OPTIONS允许客户端查看服务器的性能。
8TRACE回显服务器收到的请求,主要用于测试或诊断。
9PATCH是对 PUT 方法的补充,用来对已知资源进行局部更新

我们平时使用的基本是GET、POST、PUT。

2.http组成

根据结构http可看作由URL、HEAD、BODY组成。
每个部分都可以有相应的参数。

url参数:

url参数直接放在url连接里,它们是以符号?开始,以&为分隔符的键值对。例如
http://example.com/api?param1=value1¶m2=value2
其中param1和param2是参数名,value1和value2是值。
在QT中赋值:

QUrl url("http://example.com/api");
QUrlQuery query;
query.addQueryItem("param1", "value1");
query.addQueryItem("param2", "value2");
url.setQuery(query);
  • 1
  • 2
  • 3
  • 4
  • 5

或者直接像上面例子中,直接把参数写进url地址里

QUrl url("http://example.com/api?param1=value1&param2=value2");
  • 1

head参数

Header参数是通过HTTP请求的Header部分传递的参数。Header参数包含在HTTP请求的Header字段中,以键值对的形式传递。
在Qt中,使用QNetworkRequest类进行设置。
一般会让我们设置Content-Type参数,如下面的API文档中

参数
Content-Typeapplication/x-www-form-urlencoded

在Qt中可以这样设置:

QNetworkRequest request(token);
request.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded");
  • 1
  • 2

关于Content-Type参数的作用:
在HTTP通信中,Content-Type参数用于指定请求或响应中所传输数据的MIME类型(Multipurpose Internet Mail Extensions,多用途Internet Mail扩展)。不同的Content-Type参数会告诉接收方如何解析和处理数据。
Content-Type类型与对应的解释见下表:

常见的媒体格式类型如下:
text/html : HTML格式
text/plain :纯文本格式
text/xml : XML格式
image/gif :gif图片格式
image/jpeg :jpg图片格式
image/png:png图片格式

以application开头的媒体格式类型:
application/xhtml+xml :XHTML格式
application/xml: XML数据格式
application/atom+xml :Atom XML聚合格式
application/json: JSON数据格式
application/pdf:pdf格式
application/msword : Word文档格式
application/octet-stream : 二进制流数据(如常见的文件下载)
application/x-www-form-urlencoded :form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)

另外一种常见的媒体格式是上传文件之时使用的:
multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式
Qt中对于不同类型的Content-Type,对数据的处理方式如下:

1.application/json
{
  "name": "John Doe",
  "age": 30,
  "email": "johndoe@example.com"
}
//注意此时的base64中的/+符号不需要转化
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
2.application/x-www-form-urlencoded
name=John%20Doe&age=30&email=johndoe%40example.com
//注意此时的base64中的/+符号需要转化
  • 1
  • 2
3.multipart/form-data
--boundary
Content-Disposition: form-data; name="name"

John Doe
--boundary
Content-Disposition: form-data; name="file"; filename="example.txt"
Content-Type: text/plain

This is a sample file.
--boundary--
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
4.text/plain
name: John Doe
age: 30
email: johndoe@example.com
  • 1
  • 2
  • 3
以上最常用的为1和2

body参数

Body参数是通过HTTP请求的消息正文(Body)中传递的参数。这种方式常用于POST、PUT等需要传递大量数据的请求。在Qt中,可以使用QNetworkAccessManager类来发送HTTP请求,并通过QByteArray或QHttpMultiPart来设置和发送Body参数。
这里我们只介绍用QByteArray来设置body参数,因为后者只是比前者多了几个步骤。

QByteArray bodyData = "param1=value1&param2=value2";
···
QNetworkReply *reply = manager.post(request, bodyData);
//request为上面的QNetworkRequest,manager是QNetworkAccessManager
  • 1
  • 2
  • 3
  • 4

具体的使用方法我们下面会介绍。

二、Qt中使用http

1.Qt中关于http的类

QNetworkAccessManager:http中最主要的类,负责对http请求的get、post等操作。
QNetworkRequest:http请求体类,包含head信息、body信息。
QUrl:存放url信息。
QNetworkReply:负责接收http返回消息。

2.消息处理中要用到的Json相关类

QJsonDocument:json文档。
QJsonObject:json对象。
QJsonValue:json值。

3.API文档解读

本文以百度api的图像无损放大为例,api文档连接:百度API图像无损放大
请求说明
请求示例
HTTP 方法:POST
请求URL: https://aip.baidubce.com/rest/2.0/image-process/v1/image_quality_enhance
URL参数:
参数 值
access_token 通过API Key和Secret Key获取的access_token,参考“Access Token获取”

首先文档最开头规定了http方法为POST,并且告诉我们URL地址
这里的access_token参数需要我们单独去获取。

获取access_token的步骤:

(1)申请、购买api服务(很多api是可以免费领用的)
(2)到百度智能云控制台创建应用,获得apikey和secretkey
(3)根据鉴权中心的文档,获得access_token

access_token的获取比较简单,只需要设置url参数即可。Qt中例子如下

    manager = new QNetworkAccessManager;
    QUrl token("https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=你自己的apikey&client_secret=你自己的secretkey");
    QNetworkRequest request(token);
    request.setHeader(QNetworkRequest::ContentTypeHeader,"application/json");
    QByteArray ba;
    QNetworkReply *reply = manager->post(request,ba);
    while (!reply->isFinished()) {
        qApp->processEvents();
    }
    QByteArray res = reply->readAll();
    QJsonDocument doc = QJsonDocument::fromJson(res);
    QJsonObject obj = doc.object();
    QJsonValue va = obj.value("access_token");
    QString access_token = va.toString();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

我们回到图像放大的文档。根据刚才获取到的access_token,可以完成url和head的设置。

QUrl url("https://aip.baidubce.com/rest/2.0/image-process/v1/image_quality_enhance?access_token="+access_token);
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded");
  • 1
  • 2
  • 3

继续往下,设置body数据
文档中body数据是image和url二选一,先选第一个。参数名为image,值为图片的base64编码形式。

图片转base64:

QImage image("image.png");
QByteArray byteArray;
QBuffer buffer(&byteArray);
buffer.open(QIODevice::WriteOnly);
image.save(&buffer, "PNG"); // 可以根据需要选择其他格式,如JPEG
QString base64 = byteArray.toBase64();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

我一开始调试接口时总是失败,百度返给我的失败信息是图片格式错误,我用官方调试平台生产的base64和自己本地比较,发现有些地方不一样,我自己生成的base64会带有一些符号,比如"/“,”+“,需要转化成url能接受的符号,比如”/“是”%2F",“+“是”%3D”,我用QString::replace进行替换后就成功了,后来发现QUrl类中自带了一个方法,能把字符串处理成url可接受的格式。在Content-Type类型为application/x-www-form-urlencoded时,需要把符号转化。
所以上面的最后一行代码修改为:

QString base64 = QUrl::toPercentEncoding(byteArray.toBase64());
  • 1

往QByteArray中放入数据,发送http请求并接收数据。

QByteArray ba = "image="+base64.toLatin1();
QNetworkReply *reply = manager->post(request,ba);
while (!reply->isFinished()) {
    qApp->processEvents();
}
QByteArray res_ba = reply->readAll();
QJsonDocument res_doc = QJsonDocument::fromJson(res_ba);
QJsonObject res_obj = res_doc.object();
QJsonValue img = res_obj.value("image");
QString base64 = img.toString();
QPixmap pix;
pix.loadFromData(QByteArray::fromBase64(base64.toLatin1()));
pix.save("D:/test.jpg","jpg");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

三、完整代码

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QUrl>
#include <QNetworkReply>
#include <QDebug>
#include <QFileDialog>
#include <QBuffer>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_open1_clicked();
    void on_zoomin_clicked();

private:
    Ui::Widget *ui;
    QNetworkAccessManager *manager;
    QString access_token;
    QString pic1;
};
#endif // WIDGET_H

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

widget.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    manager = new QNetworkAccessManager;
    QUrl token("https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=***&client_secret=***");
    QNetworkRequest request(token);
    request.setHeader(QNetworkRequest::ContentTypeHeader,"application/json");
    QByteArray ba;
    QNetworkReply *reply = manager->post(request,ba);
    while (!reply->isFinished()) {
        qApp->processEvents();
    }
    QByteArray res = reply->readAll();
    QJsonDocument doc = QJsonDocument::fromJson(res);
    QJsonObject obj = doc.object();
    QJsonValue va = obj.value("access_token");
    access_token = va.toString();
    qDebug()<<access_token;
}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_open1_clicked()
{
    QString filename = QFileDialog::getOpenFileName(this,"open file","./","*.png *.jpg");
    QFile file(filename);
    QImage img;
    img.load(filename);
    QByteArray ba;
    QBuffer bf(&ba);
    bf.open(QIODevice::WriteOnly);
    img.save(&bf,"jpg");
    pic1 = QUrl::toPercentEncoding(ba.toBase64());
    bf.close();
}

void Widget::on_zoomin_clicked()
{
    QUrl url("https://aip.baidubce.com/rest/2.0/image-process/v1/image_quality_enhance?access_token="+access_token);
    QNetworkRequest request(url);
    request.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded");
    QByteArray ba = "image="+pic1.toLatin1();
    QNetworkReply *reply = manager->post(request,ba);
    while (!reply->isFinished()) {
        qApp->processEvents();
    }
    QByteArray res_ba = reply->readAll();
    QJsonDocument res_doc = QJsonDocument::fromJson(res_ba);
    QJsonObject res_obj = res_doc.object();
    QJsonValue img = res_obj.value("image");
    QString base64 = img.toString();
    QPixmap pix;
    pix.loadFromData(QByteArray::fromBase64(base64.toLatin1()));
    pix.save("D:/test.jpg","jpg");
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65

附言

本例子中由于参数较少,直接用QByteArray装载了字符串。当参数多尤其是结构有多层时,应该用json。下面是人脸融合api的参数示例:

参数必选类型说明
versionstring服务版本 ,可选(1.0,2.0,3.0,4.0),如不传入该项则默认调用(1.0),2.0/3.0/4.0对merge_degree不生效,对融合效果要求较高可选择2.0(推荐版本),对融合结果的清晰度要求较高可选择3.0,4.0为最新版本,清晰度及融合效果均有提升,页面功能演示为2.0版本效果
alphafloat融合参数,可选范围 0-1浮点数,保留两位小数,默认(0), 只在version=4.0时才有效。0代表与目标图人脸最大程度相似(完全换脸),1 代表完全不换脸保留模版图,中间值(如0.5)为进行一般的换脸效果。该参数主要用于连续使用制作一组换脸渐变图片
image_templateobject模板图信息,要求被融合的人脸
边缘需要与图片边缘保持一定距离,
图片要求见文档底部
+imagestring模板图信息 图片的分辨率要求在1920x1080以下
+image_typestring图片类型
BASE64:图片的base64值;
URL:图片的 URL( 下载图片时可能由于网络等原因导致下载图片时间过长)
FACE_TOKEN: 人脸标识
+quality_controlstring质量控制
NONE: 不进行控制
LOW:较低的质量要求 NORMAL: 一般的质量要求
HIGH: 较高的质量要求
默认NONE
+face_locationstring指定模板图中进行人脸融合的人脸框位置 不指定时则默认使用最大的人脸
格式形如: {\"left\": 111.4,\"top\": 96.56,\"width\": 98,\"height\": 98,\"rotation\": 3}
当image_type为FACE_TOKEN时, 此参数无效, 会使用FACE_TOKEN对应的人脸
image_targetobject目标图信息,要求图片为清晰正脸
+imagestring目标图信息 图片的分辨率要求在1920x1080以下
+image_typestring图片类型
BASE64:图片的base64值;
URL:图片的 URL( 下载图片时可能由于网络等原因导致下载图片时间过长)
FACE_TOKEN: 人脸标识
+quality_controlstring质量控制
NONE: 不进行控制
LOW:较低的质量要求
NORMAL: 一般的质量要求
HIGH: 较高的质量要求
默认NONE
+face_locationstring指定目标图中进行人脸融合的人脸框位置 不指定时则默认使用最大的人脸
格式形如: {\"left\": 111.4,\"top\": 96.56,\"width\": 98,\"height\": 98,\"rotation\": 3}
当image_type为FACE_TOKEN时, 此参数无效, 会使用FACE_TOKEN对应的人脸
merge_degreestring融合度 关系到融合图与目标图的相似度 越高则越相似
LOW:较低的融合度
NORMAL: 一般的融合度
HIGH: 较高的融合度
COMPLETE: 完全融合
默认COMPLETE
positionint水印的位置,取值如下:
0-右下角
1-左下角
2-左上角
3-右上角
默认0
languageint水印的语言,取值如下:
0-中文(AI生成)
1-英文(Generated by AI)
默认0
Qt中的代码:
QUrl url("https://aip.baidubce.com/rest/2.0/face/v1/merge?access_token="+access_token);
    QNetworkRequest request(url);
    request.setHeader(QNetworkRequest::ContentTypeHeader,"application/json");
    QJsonObject obj;
    obj.insert("version","4.0");
    QJsonObject img_template;
    img_template.insert("image",pic1);
    img_template.insert("image_type","BASE64");
    QJsonObject img_target;
    img_target.insert("image",pic2);
    img_target.insert("image_type","BASE64");
    obj.insert("image_template",img_template);
    obj.insert("image_target",img_target);
    QJsonDocument doc;
    doc.setObject(obj);
    QByteArray ba=doc.toJson(QJsonDocument::Compact);
    QNetworkReply *reply = manager->post(request,ba);
    while (!reply->isFinished()) {
        qApp->processEvents();
    }
    QByteArray res = reply->readAll();
    QJsonDocument json_res = QJsonDocument::fromJson(res);
    QJsonObject json_obj = doc.object();
    QJsonObject jv = json_obj["result"].toObject();
    QJsonValue img = jv.value("merge_image");
    QString base64pic = img.toString();
    QPixmap pix;
    pix.loadFromData(QByteArray::fromBase64(base64pic.toLatin1()));
    ui->face3->setPixmap(pix);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/299625
推荐阅读
相关标签
  

闽ICP备14008679号