Qt之连接微信小程序云服务器

目录

使用的net_p是自己封装的类,内容在末尾

1、接口调用凭证

1.1、请求地址

1.2、请求参数

1.3、 返回值

 1.4、access_token 的存储与更新

1.5、代码示例

1.5.1、申请定时器

1.5.2、GetAccessToken定义

2、触发云函数

2.1、请求地址

2.2、请求参数

2.3、返回值

2.4、Tips

2.5、代码示例

3、数据库内容导出

3.1、请求地址

3.2、请求参数

3.3、返回值

3.4、导出流程

3.5、代码示例

3.5.1、申请定时器

3.5.2、申请导出,获取job_id

3.5.3、查询是否迁移完成,完成就下载

4、插入内容到数据库

4.1、请求地址

4.2、请求参数

4.3、返回值

4.4、 代码示例

5、获取文件上传链接

5.1、请求地址

5.2、请求参数

5.3、返回值

 5.4、上传链接使用说明

6、全部代码

6.1、mainwindow.h

6.2、mainwindow.c

6.3、netcommunication.h

6.4、netcommunication.c

 7、qt.network.ssl: QSslSocket::connectToHostEncrypted: TLS initialization faile

7.1、先获取当前版本

7.2、下载对应的版本

8、追加文件下载

8.1、请求地址

8.2、请求参数

8.2.1、file_list 的结构

8.3、代码示例

在云开发中主要的http api有云函数、数据库、存储,所以就以此各取典型试验了一下

详情请见:微信官方文档-HTTP API文档

非常感谢一位博主的文章,当时这个涉及到了知识盲区QHttpMultiPart,还好看到了他的博客才知道:Qt之QHttpMultiPart(上传文件到微信小程序云服务器)

本文主要就是抄袭上面两位

使用的net_p是自己封装的类,内容在末尾

1、接口调用凭证

        详情请见:微信官方文档-auth.getAccessToken

        获取小程序全局唯一后台接口调用凭据(access_token)。调用绝大多数后台接口时都需使用 access_token,开发者需要进行妥善保存。通过开发着的appid和secret获取

1.1、请求地址

https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

1.2、请求参数

属性类型默认值必填说明
grant_typestring填写 client_credential
appidstring小程序唯一凭证,即 AppID,可在「微信公众平台 - 设置 - 开发设置」页中获得。(需要已经成为开发者,且帐号没有异常状态)
secretstring小程序唯一凭证密钥,即 AppSecret,获取方式同 appid

1.3、 返回值

属性类型说明
access_tokenstring获取到的凭证
expires_innumber凭证有效时间,单位:秒。目前是7200秒之内的值。
errcodenumber错误码
errmsgstring错误信息

 1.4、access_token 的存储与更新

  • access_token 的存储至少要保留 512 个字符空间;
  • access_token 的有效期目前为 2 个小时,需定时刷新,重复获取将导致上次获取的 access_token 失效;

1.5、代码示例

1.5.1、申请定时器

因为你要两个小时刷新一次

Token_timer = new QTimer(this);
connect(Token_timer, &QTimer::timeout, this, &MainWindow::GetAccessToken);
Token_timer->stop();

1.5.2、GetAccessToken定义

    /* 开发者小程序后台的appid */
    QString appid = "xxxxxxxx";
    /* 开发者小程序后台的secret */
    QString secret = "xxxxxxxx";

    QString url = (tr("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%1&secret=%2").arg(appid,secret));
    ui->textBrowser->append("获取微信后台接口调用凭据ACCESS_TOKEN");
    if (net_p->PostHttp(url,"", 1)) {
        QJsonDocument jd = net_p->getData();
        Access_Token = jd["access_token"].toString();
        int Access_Token_expries = jd["expires_in"].toInt()-200;
        ui->textBrowser->append("获取微信后台接口调用凭据ACCESS_TOKEN成功");
        ui->textBrowser->append("Access_Token: "+ Access_Token);
        Token_timer->setInterval(Access_Token_expries*1000);
        if(!Token_timer->isActive()){
            Token_timer->start();
        }
    }else{
        ui->textBrowser->append("获取微信后台接口调用凭据ACCESS_TOKEN失败");
    }

2、触发云函数

2.1、请求地址

POST https://api.weixin.qq.com/tcb/invokecloudfunction?access_token=ACCESS_TOKEN&env=ENV&name=FUNCTION_NAME

2.2、请求参数

属性类型默认值必填说明
access_token / cloudbase_access_tokenstring接口调用凭证
envstring云开发环境ID
namestring云函数名称
POSTBODYstring云函数的传入参数,具体结构由开发者定义。

2.3、返回值

返回的 JSON 数据包

属性类型说明
errcodenumber错误码
errmsgstring错误信息
resp_datastring云函数返回的buffer

2.4、Tips

  1. 使用本 API 触发云函数,在云函数中无法获取 OpenID 等用户相关信息,无法使用涉及用户登录态的其他API。
  2. 注意 POST BODY 部分会传递给云函数作为输入参数。
  3. 由 HTTP API 触发的云函数可以使用云调用。
  4. 由 HTTP API 触发云函数的超时时间为5s,请注意云函数的执行时间不能过长。

2.5、代码示例

/* 函数功能:获取触发云函数 */
#define POSTBODY_NULL 0
void MainWindow::on_BtnTriggerCloud_clicked()
{
    QString url = "https://api.weixin.qq.com/tcb/invokecloudfunction?";
    /* 1、一切前提:access_token已获取且有效 */
    url.append("access_token=").append(Access_Token).append("&");
    /* 2、需要触发的云函数的环境变量 */
    url.append("env=").append("xxxxxxxx").append("&");
    /* 3、需要触发的云函数的名称 */
    url.append("name=").append("GetOrderData");
    QByteArray oby("");
#if POSTBODY_NULL
    /* 4.1、POSTBODY为空 */
#else
    /* 4.2、POSTBODY不为空,自定义obj内容 */
    QJsonObject obj{
        {"Type","Get"},
        {"userOpenid","12345678"}
    };
    oby = QJsonDocument(obj).toJson();
#endif
    if (net_p->PostHttp(url,oby,5)) {
        QJsonDocument jd = net_p->getData();
        ui->textBrowser->append(jd.toJson());
    }else{
        ui->textBrowser->append("触发微信后台云函数失败");
    }
}

此处的env和name必须在url里

3、数据库内容导出

3.1、请求地址

POST https://api.weixin.qq.com/tcb/databasemigrateexport?access_token=ACCESS_TOKEN

3.2、请求参数

属性类型默认值必填说明
access_token / cloudbase_access_tokenstring接口调用凭证
envstring云环境ID
file_pathstring导出文件路径(文件会导出到公共的云存储中,可使用获取下载链接 API 获取下载链接)
file_typenumber

导出文件类型,文件格式参考数据库导入指引中的文件格式部分:

1:JSON

2:CSV

querystring导出条件

3.3、返回值

返回的 JSON 数据包

属性类型说明
errcodenumber错误码
errmsgstring错误信息
job_idnumber导出任务ID,使用数据库迁移进度查询 API 查询导出结果,获取文件下载链接。

3.4、导出流程

  1. 申请导出,返回job_id
  2. 使用job_id查询迁移是否完成
  3. 等待迁移完成,时间较长,数据很少也需要几秒钟,所以需要定时器
  4. 迁移完成,返回临时文件的url,允许下载

3.5、代码示例

3.5.1、申请定时器

    file_timer = new QTimer(this);
    connect(file_timer, &QTimer::timeout, this, &MainWindow::GetFileDownloadUrl);
    file_timer->setInterval(1000);
    file_timer->stop();

3.5.2、申请导出,获取job_id

    QString url = "https://api.weixin.qq.com/tcb/databasemigrateexport?";
    /* 1、一切前提:access_token已获取且有效 */
    url.append("access_token=").append(Access_Token);

    QString query = tr("db.collection('Orders').get()");
    QJsonObject obj{
        {"env","xxxxxxxx"},//云开发的环境变量
        {"file_path","temp.json"},
        {"file_type",1},//1:json格式;2:csv格式
        {"query",query}
    };
    QByteArray oby = QJsonDocument(obj).toJson();

    if (net_p->PostHttp(url,oby,3)) {
        QJsonDocument jd = net_p->getData();
        job_id= jd["job_id"].toInt();
        ui->textBrowser->append(jd.toJson());
        ui->textBrowser->append("job_id: "+ QString::number(job_id));
        file_timer->start();
    }else{
        ui->textBrowser->append("导出中获取job_id异常");
    }

3.5.3、查询是否迁移完成,完成就下载

void MainWindow::GetFileDownloadUrl()
{
    QString url = "https://api.weixin.qq.com/tcb/databasemigratequeryinfo?";
    url.append("access_token=").append(Access_Token);
    QJsonObject obj{
        {"env","xxxxxxx"},//云开发的环境变量
        {"job_id",job_id},
    };
    QByteArray oby = QJsonDocument(obj).toJson();

    if (net_p->PostHttp(url,oby,3)) {
        QJsonDocument jd = net_p->getData();
        file_url = jd["file_url"].toString();
        ui->textBrowser->append(jd.toJson());
        ui->textBrowser->append(file_url);
        if(!file_url.isEmpty()){
            file_timer->stop();
            ui->textBrowser->append("导出中获取文件下载进行状态:"+jd["status"].toString());
            ui->textBrowser->append("导出中获取文件下载失败个数:"+QString::number(jd["record_fail"].toInt()));
            ui->textBrowser->append("导出中获取文件下载成功个数:"+QString::number(jd["record_success"].toInt()));
            /* 注意:此处开始变成get而不是post */
            if (net_p->GetHttp(file_url,10)) {
                QString path = QDir::currentPath()+"/temp.json";
                QFile file(path);
                file.open(QIODevice::WriteOnly);
                file.write(net_p->getArray());
                file.close();
                ui->textBrowser->append("导出中下载文件完成");
            }else{
                ui->textBrowser->append("导出中下载文件异常");
            }
        }else{
            ui->textBrowser->append("导出中获取文件下载进行状态:"+jd["status"].toString());
        }

    }else{
        ui->textBrowser->append("导出中获取文件下载地址异常");
    }
}

4、插入内容到数据库

4.1、请求地址

POST https://api.weixin.qq.com/tcb/databaseadd?access_token=ACCESS_TOKEN

4.2、请求参数

属性类型默认值必填说明
access_token / cloudbase_access_tokenstring接口调用凭证
envstring云环境ID
querystring数据库操作语句

4.3、返回值

属性类型说明
errcodenumber错误码
errmsgstring错误信息
id_listArray.<string>插入成功的数据集合主键_id

4.4、 代码示例

    QString url = "https://api.weixin.qq.com/tcb/databaseadd?";
    /* 1、一切前提:access_token已获取且有效 */
    url.append("access_token=").append(Access_Token);
    QString query = tr("db.collection('Orders').add({\
                        data: {\
                            Address: \"杭州市富阳区金桥北路1号东方茂F1\",\
                            Name: \"肯德基(东方茂餐厅)\",\
                            Phone: \"0571-63371023\",\
                            PerCapita: \"31.0\",\
                            Comment: \"12\"}\
                        })");
    QJsonObject obj{
        {"env","xxxxxxxxx"},
        {"query",query}
    };
    QByteArray oby = QJsonDocument(obj).toJson();

    if (net_p->PostHttp(url,oby,3)) {
        QJsonDocument jd = net_p->getData();

        ui->textBrowser->append(jd.toJson());

        int errcode = jd["errcode"].toInt();
        if(errcode == 0){
            ui->textBrowser->append("数据库插入成功");
        }else{
            ui->textBrowser->append("数据库插入异常");
        }
    }else{
        ui->textBrowser->append("数据库插入发送异常");
    }

5、获取文件上传链接

5.1、请求地址

POST https://api.weixin.qq.com/tcb/uploadfile?access_token=ACCESS_TOKEN

5.2、请求参数

属性类型默认值必填说明
access_token / cloudbase_access_tokenstring接口调用凭证
envstring云环境ID
pathstring上传路径

5.3、返回值

属性类型说明
errcodenumber错误码
errmsgstring错误信息
urlstring上传url
tokenstringtoken
authorizationstringauthorization
file_idstring文件ID
cos_file_idstringcos文件ID

 5.4、上传链接使用说明

用户获取到返回数据后,需拼装一个 HTTP POST 请求,其中 url 为返回包的 url 字段,Body 部分格式为 multipart/form-data,具体内容如下:

keyvalue说明
keythis/is/a/example/file.path请求包中的 path 字段
Signatureq-sign-algorithm=sha1&q-ak=AKID9...返回数据的 authorization 字段
x-cos-security-tokenCukha70zkXIBqkh1Oh...返回数据的 token 字段
x-cos-meta-fileidHDze32/qZENCwWi5...返回数据的 cos_file_id 字段
file文件内容文件的二进制内容

这里真的太重要了,这个如果对于小程序来说的访问其实很简单,但是在Qt上需要使用 QHttpMultiPart

    QString url = "https://api.weixin.qq.com/tcb/uploadfile?";
    /* 1、一切前提:access_token已获取且有效 */
    url.append("access_token=").append(Access_Token);
    QString path = "temp.json";//云存储的文件路径
    QJsonObject obj{
        {"env","xxxxxx"},
        {"path",path}/* 自定义文件路径 */
    };
    QByteArray oby = QJsonDocument(obj).toJson();

    if (net_p->PostHttp(url,oby,3)) {
        QJsonDocument jd = net_p->getData();
        int errcode = jd["errcode"].toInt();
        ui->textBrowser->append(jd.toJson());
        if(errcode == 0){
            ui->textBrowser->append("文件上传链接返回成功");

            QFile f("D:/temp.json");//本地需要上传的文件路径
            f.open(QIODevice::ReadOnly);
            QByteArray ba = f.readAll();
            f.close();
            /* 没有返回值,也不知道为什么,文档没讲的我也不会啊 */
            net_p->PostHttpMultiPart(path,ba,jd);
        }else{
            ui->textBrowser->append("文件上传链接返回异常");
        }
    }else{
        ui->textBrowser->append("文件上传链接发送异常");
    }

6、全部代码

6.1、mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QTimer>
#include <QMainWindow>
#include <QNetworkRequest>

#include <QNetworkAccessManager>

class QNetworkReply;
class QNetworkAccessManager;
class NetCommunication;

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void GetAccessToken();

    void GetFileDownloadUrl();

    void on_BtnAccessToken_clicked();

    void on_BtnTriggerCloud_clicked();

    void on_BtnExport_clicked();

    void on_BtnUpload_clicked();

    void on_BtnInsert_clicked();

private:
    Ui::MainWindow *ui;
    NetCommunication *net_p;
    QTimer *Token_timer;
    QTimer *file_timer;
    int Access_Token_expries;
    QString Access_Token;
    QString file_url;
    int job_id;
};

#endif // MAINWINDOW_H

6.2、mainwindow.c

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtNetwork>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include "netcommunication.h"
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    net_p = new NetCommunication(this);
    
    Token_timer = new QTimer(this);
    connect(Token_timer, &QTimer::timeout, this, &MainWindow::GetAccessToken);
    Token_timer->stop();
    
    file_timer = new QTimer(this);
    connect(file_timer, &QTimer::timeout, this, &MainWindow::GetFileDownloadUrl);
    file_timer->setInterval(1000);
    file_timer->stop();


    Access_Token = "";
    job_id = 0;
}
MainWindow::~MainWindow()
{
    delete ui;
    delete net_p;
}

/* access_token 的存储与更新
 * access_token 的存储至少要保留 512 个字符空间;
 * access_token 的有效期目前为 2 个小时,需定时刷新,重复获取将导致上次获取的 access_token 失效;
 * 建议开发者使用中控服务器统一获取和刷新 access_token,其他业务逻辑服务器所使用的 access_token 均来自于该中控服务器,不应该各自去刷新,否则容易造成冲突,导致 access_token 覆盖而影响业务;
 * access_token 的有效期通过返回的 expires_in 来传达,目前是7200秒之内的值,中控服务器需要根据这个有效时间提前去刷新。在刷新过程中,中控服务器可对外继续输出的老 access_token,此时公众平台后台会保证在5分钟内,新老 access_token 都可用,这保证了第三方业务的平滑过渡;
 * access_token 的有效时间可能会在未来有调整,所以中控服务器不仅需要内部定时主动刷新,还需要提供被动刷新 access_token 的接口,这样便于业务服务器在 API 调用获知 access_token 已超时的情况下,可以触发 access_token 的刷新流程。
*/
void MainWindow::GetAccessToken(){
    /* 开发者小程序后台的appid */
    QString appid = "xxxxxxxx";
    /* 开发者小程序后台的secret */
    QString secret = "xxxxxxxx";

    QString url = (tr("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%1&secret=%2").arg(appid,secret));
    ui->textBrowser->append("获取微信后台接口调用凭据ACCESS_TOKEN");
    if (net_p->PostHttp(url,"", 1)) {
        QJsonDocument jd = net_p->getData();
        Access_Token = jd["access_token"].toString();
        int Access_Token_expries = jd["expires_in"].toInt()-200;
        ui->textBrowser->append("获取微信后台接口调用凭据ACCESS_TOKEN成功");
        ui->textBrowser->append("Access_Token: "+ Access_Token);
        ui->textBrowser->append("Access_Token_expries: "+ QString::number(Access_Token_expries));
        ui->textBrowser->append(jd.toJson());
        Token_timer->setInterval(Access_Token_expries*1000);
        if(!Token_timer->isActive()){
            Token_timer->start();
        }
    }else{
        ui->textBrowser->append("获取微信后台接口调用凭据ACCESS_TOKEN失败");
    }
}
/* 函数功能:获取微信后台接口 */
void MainWindow::on_BtnAccessToken_clicked()
{
    GetAccessToken();
}
/* 函数功能:获取触发云函数 */
#define POSTBODY_NULL 0
void MainWindow::on_BtnTriggerCloud_clicked()
{
    QString url = "https://api.weixin.qq.com/tcb/invokecloudfunction?";
    /* 1、一切前提:access_token已获取且有效 */
    url.append("access_token=").append(Access_Token).append("&");
    /* 2、需要触发的云函数的环境变量 */
    url.append("env=").append("xxxxxxxx").append("&");
    /* 3、需要触发的云函数的名称 */
    url.append("name=").append("GetOrderData");
    QByteArray oby("");
#if POSTBODY_NULL
    /* 4.1、POSTBODY为空 */
#else
    /* 4.2、POSTBODY不为空,自定义obj内容 */
    QJsonObject obj{
        {"Type","Get"},
        {"userOpenid","12345678"}
    };
    qDebug() << "obj : " << obj;
    qDebug() << "oby : " << oby;
    oby = QJsonDocument(obj).toJson();
#endif
    if (net_p->PostHttp(url,oby,3)) {
        QJsonDocument jd = net_p->getData();
        ui->textBrowser->append(jd.toJson());
    }else{
        ui->textBrowser->append("触发微信后台云函数失败");
    }
}

void MainWindow::GetFileDownloadUrl()
{
    QString url = "https://api.weixin.qq.com/tcb/databasemigratequeryinfo?";
    url.append("access_token=").append(Access_Token);
    QJsonObject obj{
        {"env","xxxxxxxx"},
        {"job_id",job_id},
    };
    QByteArray oby = QJsonDocument(obj).toJson();

    if (net_p->PostHttp(url,oby,3)) {
        QJsonDocument jd = net_p->getData();
        file_url = jd["file_url"].toString();
        ui->textBrowser->append(jd.toJson());
        ui->textBrowser->append(file_url);
        if(!file_url.isEmpty()){
            file_timer->stop();
            ui->textBrowser->append("导出中获取文件下载进行状态:"+jd["status"].toString());
            ui->textBrowser->append("导出中获取文件下载失败个数:"+QString::number(jd["record_fail"].toInt()));
            ui->textBrowser->append("导出中获取文件下载成功个数:"+QString::number(jd["record_success"].toInt()));
            /* 注意:此处开始变成get而不是post */
            if (net_p->GetHttp(file_url,10)) {
                QString path = QDir::currentPath()+"/temp.json";
                QFile file(path);
                file.open(QIODevice::WriteOnly);
                file.write(net_p->getArray());
                file.close();
                ui->textBrowser->append("导出中下载文件完成");
            }else{
                ui->textBrowser->append("导出中下载文件异常");
            }
        }else{
            ui->textBrowser->append("导出中获取文件下载进行状态:"+jd["status"].toString());
        }

    }else{
        ui->textBrowser->append("导出中获取文件下载地址异常");
    }
}

void MainWindow::on_BtnExport_clicked()
{
    QString url = "https://api.weixin.qq.com/tcb/databasemigrateexport?";
    /* 1、一切前提:access_token已获取且有效 */
    url.append("access_token=").append(Access_Token);

    QString query = tr("db.collection('Orders').get()");
    QJsonObject obj{
        {"env","xxxxxxxx"},
        {"file_path","temp.json"},
        {"file_type",1},//1:json格式;2:csv格式
        {"query",query}
    };
    QByteArray oby = QJsonDocument(obj).toJson();

    if (net_p->PostHttp(url,oby,3)) {
        QJsonDocument jd = net_p->getData();
        job_id= jd["job_id"].toInt();
        ui->textBrowser->append(jd.toJson());
        ui->textBrowser->append("job_id: "+ QString::number(job_id));
        file_timer->start();
    }else{
        ui->textBrowser->append("导出中获取job_id异常");
    }
}

void MainWindow::on_BtnUpload_clicked()
{
    QString url = "https://api.weixin.qq.com/tcb/uploadfile?";
    /* 1、一切前提:access_token已获取且有效 */
    url.append("access_token=").append(Access_Token);
    QString path = "temp.json";
    QJsonObject obj{
        {"env","xxxxxxxx"},
        {"path",path}/* 自定义文件路径 */
    };
    QByteArray oby = QJsonDocument(obj).toJson();

    if (net_p->PostHttp(url,oby,3)) {
        QJsonDocument jd = net_p->getData();
        int errcode = jd["errcode"].toInt();
        ui->textBrowser->append(jd.toJson());
        if(errcode == 0){
            ui->textBrowser->append("文件上传链接返回成功");

            QFile f("D:/temp.json");
            f.open(QIODevice::ReadOnly);
            QByteArray ba = f.readAll();
            f.close();
            /* 没有返回值,也不知道为什么,文档没讲的我也不会啊 */
            net_p->PostHttpMultiPart(path,ba,jd);
        }else{
            ui->textBrowser->append("文件上传链接返回异常");
        }
    }else{
        ui->textBrowser->append("文件上传链接发送异常");
    }
}

/*
 *  Address: 杭州市富阳区金桥北路1号东方茂F1
    Name: 肯德基(东方茂餐厅)
    Phone: 0571-63371023
    PerCapita: 31.0
    Comment: 12
*/
void MainWindow::on_BtnInsert_clicked()
{
    QString url = "https://api.weixin.qq.com/tcb/databaseadd?";
    /* 1、一切前提:access_token已获取且有效 */
    url.append("access_token=").append(Access_Token);
    QString query = tr("db.collection('Orders').add({\
                        data: {\
                            Address: \"杭州市富阳区金桥北路1号东方茂F1\",\
                            Name: \"肯德基(东方茂餐厅)\",\
                            Phone: \"0571-63371023\",\
                            PerCapita: \"31.0\",\
                            Comment: \"12\"}\
                        })");
    QJsonObject obj{
        {"env","xxxxxxxx"},
        {"query",query}
    };
    QByteArray oby = QJsonDocument(obj).toJson();

    if (net_p->PostHttp(url,oby,3)) {
        QJsonDocument jd = net_p->getData();

        ui->textBrowser->append(jd.toJson());

        int errcode = jd["errcode"].toInt();
        if(errcode == 0){
            ui->textBrowser->append("数据库插入成功");
        }else{
            ui->textBrowser->append("数据库插入异常");
        }
    }else{
        ui->textBrowser->append("数据库插入发送异常");
    }
}

6.3、netcommunication.h

#ifndef NETCOMMUNICATION_H
#define NETCOMMUNICATION_H

#include <QObject>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QJsonParseError>
#include <QtNetwork>
#include <QNetworkRequest>
#include <QUrl>
#include <QByteArray>
#include <QDebug>
#include <QDateTime>


#define false false
#define true  true

extern bool NetWorkStatus;//网络

class NetCommunication : public QObject
{
    Q_OBJECT
public:
    explicit NetCommunication(QObject *parent = nullptr);
    ~NetCommunication(){}

    QJsonDocument getData();
    QByteArray getArray();

    bool PostHttp(const QString address, const QByteArray &postStr, int s_time);

    bool GetHttp(const QString address, int s_time);

    bool PostHttpMultiPart(QString path, QByteArray fileData, QJsonDocument jd);
signals:

public slots:

private:
    QNetworkAccessManager *accessManager;
    QJsonDocument ServerReply;
    QByteArray ServerArray;
    QNetworkRequest *request;
    bool replyFinished(QNetworkReply *reply);


};

#endif // NETCOMMUNICATION_H

6.4、netcommunication.c

#include "netcommunication.h"
#include <QApplication>

bool NetWorkStatus = false;//网络状态

NetCommunication::NetCommunication(QObject *parent) :
    QObject(parent)
{
    accessManager = new QNetworkAccessManager(this);
    request = new QNetworkRequest();

}


bool NetCommunication::PostHttp(const QString address, const QByteArray &postStr, int s_time)
{
    request->setUrl(QUrl(address));
    request->setHeader(QNetworkRequest::ContentTypeHeader, "application/json ;encoding=utf-8");
    QByteArray postData = postStr;
    QNetworkReply *pReply = accessManager->post(*request, postData);

    QEventLoop loop;
    QTimer timer;
    connect(accessManager, SIGNAL(finished(QNetworkReply*)), &loop, SLOT(quit()));
    connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
    timer.start((s_time * 1000));//定时2s暂定
    loop.exec();

    if (timer.isActive()){
        timer.stop();
    }else{
        return false;
    }
    return replyFinished(pReply);
}

bool NetCommunication::GetHttp(const QString address,int s_time)
{
    request->setUrl(QUrl(address));
    QNetworkReply *pReply = accessManager->get(*request);
    request->setHeader(QNetworkRequest::ContentTypeHeader, "application/json ;encoding=utf-8");

    QEventLoop loop;
    QTimer timer;
    connect(accessManager, SIGNAL(finished(QNetworkReply*)), &loop, SLOT(quit()));
    connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
    timer.start((s_time * 1000));//定时2s暂定
    loop.exec();

    if (QNetworkReply::NoError == pReply->error()) {
        ServerArray = pReply->readAll();
        timer.stop();
        pReply->deleteLater();
        pReply = nullptr;
        return true;
    }
    return false;
}

bool NetCommunication::PostHttpMultiPart(QString path,QByteArray fileData, QJsonDocument jd)
{
    QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
    //此处boundary不能省! 需要和QHttpMultiPart中的一致
    request->setHeader(QNetworkRequest::ContentTypeHeader,"multipart/form-data;boundary=boundary_.oOo._");

    QHttpPart keyPart;
    keyPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"key\""));
    keyPart.setBody(path.toUtf8());

    QHttpPart authorizationPart;
    authorizationPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"Signature\""));
    authorizationPart.setBody(jd["authorization"].toString().toUtf8());

    QHttpPart tokenPart;
    tokenPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"x-cos-security-token\""));
    tokenPart.setBody(jd["token"].toString().toUtf8());

    QHttpPart fileidPart;
    fileidPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"x-cos-meta-fileid\""));
    fileidPart.setBody(jd["cos_file_id"].toString().toUtf8());

    QHttpPart filePart;
    filePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data;name=\"file\""));
    filePart.setBody(fileData);

    multiPart->append(keyPart);
    multiPart->append(authorizationPart);
    multiPart->append(tokenPart);
    multiPart->append(fileidPart);
    multiPart->append(filePart);

    request->setUrl(QUrl(jd["url"].toString()));
    QNetworkReply *pReply = accessManager->post(*request, multiPart);

    QEventLoop loop;
    QTimer timer;
    connect(accessManager, SIGNAL(finished(QNetworkReply*)), &loop, SLOT(quit()));
    connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
    timer.start((10 * 1000));//定时2s暂定
    loop.exec();

    multiPart->deleteLater();
    multiPart = nullptr;
    if (timer.isActive()){
        timer.stop();
    }else{
        return false;
    }
    return replyFinished(pReply);

}


bool NetCommunication::replyFinished(QNetworkReply *reply)
{
    if (QNetworkReply::NoError == reply->error()) {
        QTextCodec *codec = QTextCodec::codecForName("utf-8");
        QByteArray ba = reply->readAll();
        QString all = codec->toUnicode(ba);
        QJsonDocument js = QJsonDocument::fromJson(all.toUtf8());

        ServerReply = js;
        if ("" != all){
            NetWorkStatus = true;
        }else{
            NetWorkStatus = false;
            qDebug() << "ba: " << ba;
        }
    }else{
        NetWorkStatus = false;
    }

    reply->deleteLater();
    reply = nullptr;
    return NetWorkStatus;
}

QJsonDocument NetCommunication::getData()
{
    return ServerReply;
}

QByteArray NetCommunication::getArray()
{
    return ServerArray;
}



有需要的可以下载:

链接:https://pan.baidu.com/s/1yYIvyAXknPYgm0i088E-DA?pwd=8kwb 
提取码:8kwb

 7、qt.network.ssl: QSslSocket::connectToHostEncrypted: TLS initialization faile

7.1、先获取当前版本

输出当前QT支持的openSSL版本
 
 qDebug()<<"QSslSocket="<<QSslSocket::sslLibraryBuildVersionString();
 判断系统是否支持OpenSSL
 如果此平台支持SSL,则返回true; 否则,返回false。 如果平台不支持SSL,则套接字将在连接阶段失败。不支持就需要看下面的解决方法。
qDebug() << "OpenSSL支持情况:" << QSslSocket::supportsSsl();

我的当前版本是

QSslSocket= "OpenSSL 1.1.1b  26 Feb 2019"

 所以我等会下载的就会是OpenSSL v1.1.1o的版本

7.2、下载对应的版本

openssl下载地址:

http://slproweb.com/products/Win32OpenSSL.html

        根据自己使用的QT编译器时32位还是64位,对应下载安装包。将下载的安装包进行安装,安装到第二个选项时,选择安装到指定的/bin目录下。安装之后,找到安装目录下的两个文件(其中我的是libcrypto-1_1.dll 和libssl-1_1.dll),拷贝到QT编译器目录下即可。

8、追加文件下载

今天在使用文件下载时,官方文档是格式是这样的

8.1、请求地址

POST https://api.weixin.qq.com/tcb/batchdownloadfile?access_token=ACCESS_TOKEN

8.2、请求参数

属性类型默认值必填说明
access_token / cloudbase_access_tokenstring接口调用凭证
envstring云环境ID
file_listArray.<Object>文件列表

8.2.1、file_list 的结构

属性类型默认值必填说明
fileidstring文件ID
max_agenumber下载链接有效期

但是我发现加了 max_age那么一直提示错误代码:

-501007云资源通用错误:参数错误

所以去除了之后一切正常,怀疑max_age是浏览器使用的吧

8.3、代码示例

QString url = "https://api.weixin.qq.com/tcb/batchdownloadfile?access_token="+Access_Token;
    QJsonObject file{{"fileid","xxxxxxxxx/temp.json"}};//文件的fileid,前缀是固定值
    QJsonArray array ;
    array.append(file);
    QJsonObject obj{
        {"env","xxxxxxxxxx"},
        {"file_list",array}/* 自定义文件路径 */
    };
    QByteArray oby = QJsonDocument(obj).toJson();

    if (net_p->PostHttp(url,oby,3)) {
        QJsonDocument jd = net_p->getData();
        int errcode = jd["errcode"].toInt();
        if(errcode == 0){
            qDebug("文件上传链接返回成功");
            QJsonObject download_obj = (jd["file_list"].toArray()).first().toObject();
            QString download_url = download_obj["download_url"].toString();
            qDebug() << "download_url: " << download_url;
            if (net_p->GetHttp(download_url,10)) {
                QFile file("D:/temp1.json");
                file.open(QIODevice::WriteOnly);
                file.write(net_p->getArray());
                file.close();
                qDebug() << ("下载文件完成");
                messagebox(tr("提示"),tr("下载文件完成!!!"));
            }else{
                qDebug() << ("下载文件异常");
            }
        }else{
            qDebug("文件下载链接返回异常");
        }
    }else{
        qDebug("文件下载链接发送异常");
    }

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值