This commit is contained in:
zhuzichu 2023-07-26 17:48:35 +08:00
parent 502044ebd2
commit 42f058ca69
5 changed files with 277 additions and 180 deletions

View File

@ -7,152 +7,152 @@ import QtQuick.Dialogs
import FluentUI import FluentUI
import "qrc:///example/qml/component" import "qrc:///example/qml/component"
FluScrollablePage{ FluContentPage{
title:"Http" title:"Http"
FluHttp{ FluHttp{
id:http_get id:http
url:"https://api.github.com/search/repositories"
onStart: {
showLoading()
}
onFinish: {
hideLoading()
}
onError:
(status,errorString)=>{
console.debug(status+"->"+errorString)
showError(errorString)
}
onSuccess:
(result)=>{
window_result.result = result
window_result.show()
}
} }
FluHttp{ ListModel{
id:http_post id:data_model
url:"https://www.wanandroid.com/article/query/0/json" ListElement{
onStart: { name:"Get请求"
showLoading() onClickListener : function(){
} var callable = {}
onFinish: { callable.onStart = function(){
hideLoading() showLoading()
} }
onError: callable.onFinish = function(){
(status,errorString)=>{ hideLoading()
console.debug(status+"->"+errorString) }
showError(errorString) callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
http.get("https://httpbingo.org/get",callable)
} }
onSuccess: }
(result)=>{ ListElement{
window_result.result = result name:"Post表单请求"
window_result.show() onClickListener : function(){
var callable = {}
callable.onStart = function(){
showLoading()
}
callable.onFinish = function(){
hideLoading()
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
var param = {}
param.custname = "朱子楚"
param.custtel = "1234567890"
param.custemail = "zhuzichu520@gmail.com"
http.post("https://httpbingo.org/post",callable,param)
} }
}
ListElement{
name:"Post Json请求"
onClickListener : function(){
var callable = {}
callable.onStart = function(){
showLoading()
}
callable.onFinish = function(){
hideLoading()
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
var param = {}
param.custname = "朱子楚"
param.custtel = "1234567890"
param.custemail = "zhuzichu520@gmail.com"
http.postJson("https://httpbingo.org/post",callable,param)
}
}
ListElement{
name:"Post String请求"
onClickListener : function(){
var callable = {}
callable.onStart = function(){
showLoading()
}
callable.onFinish = function(){
hideLoading()
}
callable.onSuccess = function(result){
text_info.text = result
console.debug(result)
}
callable.onError = function(status,errorString){
console.debug(status+";"+errorString)
}
var param = "我命由我不由天"
http.postString("https://httpbingo.org/post",callable,param)
}
}
} }
FluHttp{
id:http_download ListView{
url:"http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" id:list_view
// url:"https://www.w3school.com.cn/example/html5/mov_bbb.mp4" width: 160
onStart: { clip: true
btn_download.disabled = true anchors{
top: parent.top
topMargin: 20
bottom: parent.bottom
left: parent.left
} }
onFinish: { model:data_model
btn_download.disabled = false delegate: FluButton{
btn_download.text = "下载文件" implicitWidth: ListView.view.width
text_file_size.text = "" implicitHeight: 30
text: model.name
onClicked: {
model.onClickListener()
}
} }
onDownloadProgress:
(recv,total)=>{
var locale = Qt.locale()
var precent = (recv/total * 100).toFixed(0) + "%"
console.debug(precent)
btn_download.text = "下载中..."+precent
text_file_size.text = "%1/%2".arg(locale.formattedDataSize(recv)).arg(locale.formattedDataSize(total))
}
onError:
(status,errorString)=>{
showError(errorString)
}
onSuccess:
(result)=>{
showSuccess(result)
}
} }
FluArea{ FluArea{
Layout.fillWidth: true anchors{
Layout.topMargin: 20 top: list_view.top
height: 160 bottom: list_view.bottom
paddings: 10 left: list_view.right
right: parent.right
ColumnLayout{ }
spacing: 14 Flickable{
anchors.verticalCenter: parent.verticalCenter clip: true
FluButton{ id:scrollview
text:"Get请求" width: parent.width
onClicked: { height: parent.height
http_get.get({q:"FluentUI"}) contentWidth: width
} contentHeight: text_info.height
ScrollBar.vertical: FluScrollBar {}
FluText{
id:text_info
width: scrollview.width
wrapMode: Text.WrapAnywhere
padding: 14
} }
FluButton{
text:"Post请求"
onClicked: {
http_post.post({k:"jitpack"})
}
}
RowLayout{
FluButton{
id:btn_download
text:disabled ? "下载中..." : "下载文件"
onClicked: {
file_dialog.open()
}
}
FluText{
id:text_file_size
Layout.alignment: Qt.AlignVCenter
}
}
} }
} }
FolderDialog {
id: file_dialog
currentFolder: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0]
onAccepted: {
var path = FluTools.toLocalPath(currentFolder)+ "/big_buck_bunny.mp4"
http_download.download(path)
}
}
Window{
property string result : ""
id:window_result
width: 600
height: 400
color: FluTheme.dark ? Qt.rgba(0,0,0,1) : Qt.rgba(1,1,1,1)
Item{
anchors.fill: parent
Flickable{
id:scrollview
width: parent.width
height: parent.height
contentWidth: width
contentHeight: text_info.height
ScrollBar.vertical: FluScrollBar {}
FluText{
id:text_info
width: scrollview.width
wrapMode: Text.WrapAnywhere
text:window_result.result
padding: 14
}
}
}
}
} }

View File

@ -6,6 +6,7 @@
#include <QUrlQuery> #include <QUrlQuery>
#include <QHttpMultiPart> #include <QHttpMultiPart>
#include <QJsonDocument> #include <QJsonDocument>
#include "MainThread.h"
#include "FluApp.h" #include "FluApp.h"
FluHttp::FluHttp(QObject *parent) FluHttp::FluHttp(QObject *parent)
@ -31,15 +32,15 @@ void FluHttp::handleReply(QNetworkReply* reply){
_cache.append(reply); _cache.append(reply);
} }
void FluHttp::post(QVariantMap params,QVariantMap headers){ void FluHttp::post(QString url,QJSValue callable,QVariantMap params,QVariantMap headers){
QVariantMap data = invokeIntercept(params,headers,"post").toMap(); QVariantMap data = invokeIntercept(params,headers,"post").toMap();
QThreadPool::globalInstance()->start([=](){ QThreadPool::globalInstance()->start([=](){
Q_EMIT start(); onStart(callable);
for (int i = 0; i < retry(); ++i) { for (int i = 0; i < retry(); ++i) {
QNetworkAccessManager manager; QNetworkAccessManager manager;
manager.setTransferTimeout(timeout()); manager.setTransferTimeout(timeout());
QUrl url(_url); QUrl _url(url);
QNetworkRequest request(url); QNetworkRequest request(_url);
addHeaders(&request,data["headers"].toMap()); addHeaders(&request,data["headers"].toMap());
QHttpMultiPart multiPart(QHttpMultiPart::FormDataType); QHttpMultiPart multiPart(QHttpMultiPart::FormDataType);
QString contentType = QString("multipart/form-data;boundary=%1").arg(multiPart.boundary()); QString contentType = QString("multipart/form-data;boundary=%1").arg(multiPart.boundary());
@ -69,28 +70,30 @@ void FluHttp::post(QVariantMap params,QVariantMap headers){
reply->deleteLater(); reply->deleteLater();
reply = nullptr; reply = nullptr;
if (isSuccess) { if (isSuccess) {
Q_EMIT success(result); onSuccess(callable,result);
break; break;
}else{ }else{
if(i == retry()-1){ if(i == retry()-1){
Q_EMIT error(status,errorString); onError(callable,status,errorString);
} }
} }
} }
Q_EMIT finish(); onFinish(callable);
}); });
} }
void FluHttp::postString(QString params,QVariantMap headers){ void FluHttp::postString(QString url,QJSValue callable,QString params,QVariantMap headers){
QVariantMap data = invokeIntercept(params,headers,"postString").toMap(); QVariantMap data = invokeIntercept(params,headers,"postString").toMap();
QThreadPool::globalInstance()->start([=](){ QThreadPool::globalInstance()->start([=](){
Q_EMIT start(); onStart(callable);
for (int i = 0; i < retry(); ++i) { for (int i = 0; i < retry(); ++i) {
QNetworkAccessManager manager; QNetworkAccessManager manager;
manager.setTransferTimeout(timeout()); manager.setTransferTimeout(timeout());
QUrl url(_url); QUrl _url(url);
QNetworkRequest request(url); QNetworkRequest request(_url);
addHeaders(&request,data["headers"].toMap()); addHeaders(&request,data["headers"].toMap());
QString contentType = QString("text/plain;charset=utf-8");
request.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
QEventLoop loop; QEventLoop loop;
QNetworkReply* reply = manager.post(request,params.toUtf8()); QNetworkReply* reply = manager.post(request,params.toUtf8());
_cache.append(reply); _cache.append(reply);
@ -106,27 +109,27 @@ void FluHttp::postString(QString params,QVariantMap headers){
reply->deleteLater(); reply->deleteLater();
reply = nullptr; reply = nullptr;
if (isSuccess) { if (isSuccess) {
Q_EMIT success(result); onSuccess(callable,result);
break; break;
}else{ }else{
if(i == retry()-1){ if(i == retry()-1){
Q_EMIT error(status,errorString); onError(callable,status,errorString);
} }
} }
} }
Q_EMIT finish(); onFinish(callable);
}); });
} }
void FluHttp::postJson(QVariantMap params,QVariantMap headers){ void FluHttp::postJson(QString url,QJSValue callable,QVariantMap params,QVariantMap headers){
QVariantMap data = invokeIntercept(params,headers,"postJson").toMap(); QVariantMap data = invokeIntercept(params,headers,"postJson").toMap();
QThreadPool::globalInstance()->start([=](){ QThreadPool::globalInstance()->start([=](){
Q_EMIT start(); onStart(callable);
for (int i = 0; i < retry(); ++i) { for (int i = 0; i < retry(); ++i) {
QNetworkAccessManager manager; QNetworkAccessManager manager;
manager.setTransferTimeout(timeout()); manager.setTransferTimeout(timeout());
QUrl url(_url); QUrl _url(url);
QNetworkRequest request(url); QNetworkRequest request(_url);
addHeaders(&request,data["headers"].toMap()); addHeaders(&request,data["headers"].toMap());
QString contentType = QString("application/json;charset=utf-8"); QString contentType = QString("application/json;charset=utf-8");
request.setHeader(QNetworkRequest::ContentTypeHeader, contentType); request.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
@ -145,28 +148,28 @@ void FluHttp::postJson(QVariantMap params,QVariantMap headers){
reply->deleteLater(); reply->deleteLater();
reply = nullptr; reply = nullptr;
if (isSuccess) { if (isSuccess) {
Q_EMIT success(result); onSuccess(callable,result);
break; break;
}else{ }else{
if(i == retry()-1){ if(i == retry()-1){
Q_EMIT error(status,errorString); onError(callable,status,errorString);
} }
} }
} }
Q_EMIT finish(); onFinish(callable);
}); });
} }
void FluHttp::get(QVariantMap params,QVariantMap headers){ void FluHttp::get(QString url,QJSValue callable,QVariantMap params,QVariantMap headers){
QVariantMap data = invokeIntercept(params,headers,"get").toMap(); QVariantMap data = invokeIntercept(params,headers,"get").toMap();
QThreadPool::globalInstance()->start([=](){ QThreadPool::globalInstance()->start([=](){
Q_EMIT start();
for (int i = 0; i < retry(); ++i) { for (int i = 0; i < retry(); ++i) {
onStart(callable);
QNetworkAccessManager manager; QNetworkAccessManager manager;
manager.setTransferTimeout(timeout()); manager.setTransferTimeout(timeout());
QUrl url(_url); QUrl _url(url);
addQueryParam(&url,data["params"].toMap()); addQueryParam(&_url,data["params"].toMap());
QNetworkRequest request(url); QNetworkRequest request(_url);
addHeaders(&request,data["headers"].toMap()); addHeaders(&request,data["headers"].toMap());
QEventLoop loop; QEventLoop loop;
QNetworkReply* reply = manager.get(request); QNetworkReply* reply = manager.get(request);
@ -183,33 +186,33 @@ void FluHttp::get(QVariantMap params,QVariantMap headers){
reply->deleteLater(); reply->deleteLater();
reply = nullptr; reply = nullptr;
if (isSuccess) { if (isSuccess) {
Q_EMIT success(result); onSuccess(callable,result);
break; break;
}else{ }else{
if(i == retry()-1){ if(i == retry()-1){
Q_EMIT error(status,errorString); onError(callable,status,errorString);
} }
} }
} }
Q_EMIT finish(); onFinish(callable);
}); });
} }
void FluHttp::download(QString path,QVariantMap params,QVariantMap headers){ void FluHttp::download(QString url,QJSValue callable,QString filePath,QVariantMap params,QVariantMap headers){
QVariantMap data = invokeIntercept(params,headers,"download").toMap(); QVariantMap data = invokeIntercept(params,headers,"download").toMap();
QThreadPool::globalInstance()->start([=](){ QThreadPool::globalInstance()->start([=](){
Q_EMIT start(); onStart(callable);
QNetworkAccessManager manager; QNetworkAccessManager manager;
QUrl url(_url); QUrl _url(url);
addQueryParam(&url,data["params"].toMap()); addQueryParam(&_url,data["params"].toMap());
QNetworkRequest request(url); QNetworkRequest request(_url);
addHeaders(&request,data["headers"].toMap()); addHeaders(&request,data["headers"].toMap());
QSharedPointer<QFile> file(new QFile(path)); QSharedPointer<QFile> file(new QFile(filePath));
QIODevice::OpenMode mode = QIODevice::WriteOnly|QIODevice::Truncate; QIODevice::OpenMode mode = QIODevice::WriteOnly|QIODevice::Truncate;
if (!file->open(mode)) if (!file->open(mode))
{ {
Q_EMIT error(-1,QString("Url: %1 %2 Non-Writable").arg(request.url().toString(),file->fileName())); onError(callable,-1,QString("Url: %1 %2 Non-Writable").arg(request.url().toString(),file->fileName()));
Q_EMIT finish(); onFinish(callable);
return; return;
} }
QEventLoop loop; QEventLoop loop;
@ -219,22 +222,22 @@ void FluHttp::download(QString path,QVariantMap params,QVariantMap headers){
QPointer<QNetworkReply> reply = manager.get(request); QPointer<QNetworkReply> reply = manager.get(request);
_cache.append(reply); _cache.append(reply);
connect(reply,&QNetworkReply::downloadProgress,this,[=](qint64 bytesReceived, qint64 bytesTotal){ connect(reply,&QNetworkReply::downloadProgress,this,[=](qint64 bytesReceived, qint64 bytesTotal){
Q_EMIT downloadProgress(bytesReceived,bytesTotal); onDownloadProgress(callable,bytesReceived,bytesTotal);
}); });
connect(reply,&QNetworkReply::readyRead,this,[=](){ connect(reply,&QNetworkReply::readyRead,this,[=](){
file->write(reply->readAll()); file->write(reply->readAll());
}); });
loop.exec(); loop.exec();
if (reply->error() == QNetworkReply::NoError) { if (reply->error() == QNetworkReply::NoError) {
Q_EMIT success(path); onSuccess(callable,filePath);
}else{ }else{
Q_EMIT error(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(),reply->errorString()); onError(callable,reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(),reply->errorString());
} }
_cache.removeOne(reply); _cache.removeOne(reply);
file->close(); file->close();
reply->deleteLater(); reply->deleteLater();
reply = nullptr; reply = nullptr;
Q_EMIT finish(); onFinish(callable);
}); });
} }
@ -271,3 +274,35 @@ void FluHttp::addHeaders(QNetworkRequest* request,const QMap<QString, QVariant>&
request->setRawHeader(iter.key().toUtf8(), iter.value().toString().toUtf8()); request->setRawHeader(iter.key().toUtf8(), iter.value().toString().toUtf8());
} }
} }
void FluHttp::onStart(const QJSValue& callable){
QJSValue onStart = callable.property("onStart");
MainThread::post([=](){onStart.call();});
}
void FluHttp::onFinish(const QJSValue& callable){
QJSValue onFinish = callable.property("onFinish");
MainThread::post([=](){onFinish.call();});
}
void FluHttp::onError(const QJSValue& callable,int status,QString errorString){
QJSValue onError = callable.property("onError");
QJSValueList args;
args<<status<<errorString;
MainThread::post([=](){onError.call(args);});
}
void FluHttp::onSuccess(const QJSValue& callable,QString result){
QJSValueList args;
args<<result;
QJSValue onSuccess = callable.property("onSuccess");
MainThread::post([=](){onSuccess.call(args);});
}
void FluHttp::onDownloadProgress(const QJSValue& callable,qint64 recv, qint64 total){
QJSValueList args;
args<<static_cast<double>(recv);
args<<static_cast<double>(total);
QJSValue onDownloadProgress = callable.property("onDownloadProgress");
MainThread::post([=](){onDownloadProgress.call(args);});
}

View File

@ -10,7 +10,6 @@
class FluHttp : public QObject class FluHttp : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY_AUTO(QString,url);
Q_PROPERTY_AUTO(int,retry); Q_PROPERTY_AUTO(int,retry);
Q_PROPERTY_AUTO(int,timeout) Q_PROPERTY_AUTO(int,timeout)
QML_NAMED_ELEMENT(FluHttp) QML_NAMED_ELEMENT(FluHttp)
@ -19,19 +18,19 @@ private:
void handleReply(QNetworkReply* reply); void handleReply(QNetworkReply* reply);
void addQueryParam(QUrl* url,const QMap<QString, QVariant>& params); void addQueryParam(QUrl* url,const QMap<QString, QVariant>& params);
void addHeaders(QNetworkRequest* request,const QMap<QString, QVariant>& params); void addHeaders(QNetworkRequest* request,const QMap<QString, QVariant>& params);
void onStart(const QJSValue& callable);
void onFinish(const QJSValue& callable);
void onError(const QJSValue& callable,int status,QString errorString);
void onSuccess(const QJSValue& callable,QString result);
void onDownloadProgress(const QJSValue& callable,qint64 recv, qint64 total);
public: public:
explicit FluHttp(QObject *parent = nullptr); explicit FluHttp(QObject *parent = nullptr);
~FluHttp(); ~FluHttp();
Q_SIGNAL void start(); Q_INVOKABLE void get(QString url,QJSValue callable,QVariantMap params = {},QVariantMap headers = {});
Q_SIGNAL void finish(); Q_INVOKABLE void post(QString url,QJSValue callable,QVariantMap params = {},QVariantMap headers = {});
Q_SIGNAL void error(int status,QString errorString); Q_INVOKABLE void postString(QString url,QJSValue callable,QString params = "",QVariantMap headers = {});
Q_SIGNAL void success(QString result); Q_INVOKABLE void postJson(QString url,QJSValue callable,QVariantMap params = {},QVariantMap headers = {});
Q_SIGNAL void downloadProgress(qint64 recv, qint64 total); Q_INVOKABLE void download(QString url,QJSValue callable,QString filePath,QVariantMap params = {},QVariantMap headers = {});
Q_INVOKABLE void get(QVariantMap params = {},QVariantMap headers = {});
Q_INVOKABLE void post(QVariantMap params = {},QVariantMap headers = {});
Q_INVOKABLE void postString(QString params = "",QVariantMap headers = {});
Q_INVOKABLE void postJson(QVariantMap params = {},QVariantMap headers = {});
Q_INVOKABLE void download(QString path,QVariantMap params = {},QVariantMap headers = {});
Q_INVOKABLE void cancel(); Q_INVOKABLE void cancel();
private: private:
QList<QPointer<QNetworkReply>> _cache; QList<QPointer<QNetworkReply>> _cache;

39
src/MainThread.cpp Normal file
View File

@ -0,0 +1,39 @@
#include "MainThread.h"
#include <QGuiApplication>
#include <QMetaMethod>
std::shared_ptr<MainThread> MainThread::createShared(QObject* bindObject)
{
return std::shared_ptr<MainThread>(new MainThread(bindObject), [=](QObject* mainThread) {
mainThread->deleteLater();
});
}
MainThread::MainThread(QObject* bindObject)
: mBindObject(bindObject)
, mIgnoreNullObject(bindObject == nullptr)
{
qRegisterMetaType<std::function<void()>>("std::function<void()>");
auto mainUIThread = qApp->thread();
if (this->thread() != mainUIThread)
{
this->moveToThread(mainUIThread);
}
}
MainThread::~MainThread()
{
}
void MainThread::post(std::function<void()> func)
{
QMetaObject::invokeMethod(createShared().get(), "mainThreadSlot", Q_ARG(std::function<void()>, func));
}
void MainThread::mainThreadSlot(std::function<void()> func)
{
if ((mIgnoreNullObject || mBindObject) && func)
{
func();
}
}

24
src/MainThread.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef MAINTHREAD_H
#define MAINTHREAD_H
#include <QObject>
#include <QPointer>
#include <QDebug>
class MainThread : public QObject
{
Q_OBJECT
public:
static void post(std::function<void()> func);
~MainThread();
private:
static std::shared_ptr<MainThread> createShared(QObject* bindObject = nullptr);
private slots:
void mainThreadSlot(std::function<void()> func);
private:
MainThread(QObject* bindObject = nullptr);
QPointer<QObject> mBindObject;
bool mIgnoreNullObject{ false };
};
#endif // MAINTHREAD_H