diff --git a/example/qml/page/T_Http.qml b/example/qml/page/T_Http.qml index 1ee6bbc3..58942ade 100644 --- a/example/qml/page/T_Http.qml +++ b/example/qml/page/T_Http.qml @@ -133,6 +133,15 @@ FluContentPage{ implicitWidth: parent.width implicitHeight: 36 text: "下载文件" + onClicked: { + folder_dialog.open() + } + } + FluButton{ + id:btn_upload + implicitWidth: parent.width + implicitHeight: 36 + text: "文件上传" onClicked: { file_dialog.open() } @@ -140,8 +149,48 @@ FluContentPage{ } } - FolderDialog { + FileDialog { id: file_dialog + onAccepted: { + var param = {} + for(var i=0;i params, QNetworkRequest request(_url); addHeaders(&request,data["headers"].toMap()); QHttpMultiPart multiPart(QHttpMultiPart::FormDataType); - QString contentType = QString("multipart/form-data;boundary=%1").arg(multiPart.boundary()); - request.setHeader(QNetworkRequest::ContentTypeHeader, contentType); for (const auto& each : data["params"].toMap().toStdMap()) { const QString& key = each.first; @@ -74,7 +72,7 @@ void FluHttp::post(QString url,QJSValue callable,QMap params, break; }else{ if(i == retry()-1){ - onError(callable,status,errorString); + onError(callable,status,errorString,result); } } } @@ -113,7 +111,7 @@ void FluHttp::postString(QString url,QJSValue callable,QString params,QMap par break; }else{ if(i == retry()-1){ - onError(callable,status,errorString); + onError(callable,status,errorString,result); } } } @@ -190,7 +188,7 @@ void FluHttp::get(QString url,QJSValue callable,QMap params,Q break; }else{ if(i == retry()-1){ - onError(callable,status,errorString); + onError(callable,status,errorString,result); } } } @@ -211,7 +209,7 @@ void FluHttp::download(QString url,QJSValue callable,QString filePath,QMapopen(mode)) { - onError(callable,-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()),""); onFinish(callable); return; } @@ -229,7 +227,7 @@ void FluHttp::download(QString url,QJSValue callable,QString filePath,QMapwrite(reply->readAll()); onSuccess(callable,filePath); }else{ - onError(callable,reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(),reply->errorString()); + onError(callable,reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(),reply->errorString(),""); } _cache.removeOne(reply); reply->deleteLater(); @@ -238,6 +236,56 @@ void FluHttp::download(QString url,QJSValue callable,QString filePath,QMap params,QMap headers){ + QMap data = invokeIntercept(params,headers,"upload").toMap(); + QThreadPool::globalInstance()->start([=](){ + onStart(callable); + QNetworkAccessManager manager; + manager.setTransferTimeout(timeout()); + QUrl _url(url); + QNetworkRequest request(_url); + addHeaders(&request,data["headers"].toMap()); + QHttpMultiPart multiPart(QHttpMultiPart::FormDataType); + for (const auto& each : data["params"].toMap().toStdMap()) + { + const QString& key = each.first; + const QString& filePath = each.second.toString(); + QFile *file = new QFile(filePath); + file->open(QIODevice::ReadOnly); + file->setParent(&multiPart); + QString dispositionHeader = QString("form-data; name=\"%1\"; filename=\"%2\"").arg(key,filePath); + QHttpPart part; + part.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream")); + part.setHeader(QNetworkRequest::ContentDispositionHeader, dispositionHeader); + part.setBodyDevice(file); + multiPart.append(part); + } + QEventLoop loop; + QNetworkReply* reply = manager.post(request,&multiPart); + _cache.append(reply); + connect(&manager,&QNetworkAccessManager::finished,this,[&loop](QNetworkReply *reply){ + loop.quit(); + }); + connect(reply,&QNetworkReply::uploadProgress,this,[=](qint64 bytesSent, qint64 bytesTotal){ + onUploadProgress(callable,bytesSent,bytesTotal); + }); + loop.exec(); + QString result = QString::fromUtf8(reply->readAll()); + int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + QString errorString = reply->errorString(); + bool isSuccess = reply->error() == QNetworkReply::NoError; + _cache.removeOne(reply); + reply->deleteLater(); + reply = nullptr; + if (isSuccess) { + onSuccess(callable,result); + }else{ + onError(callable,status,errorString,result); + } + onFinish(callable); + }); +} + QVariant FluHttp::invokeIntercept(const QVariant& params,const QVariant& headers,const QString& method){ QMap requet = { {"params",params}, @@ -282,10 +330,10 @@ void FluHttp::onFinish(const QJSValue& callable){ MainThread::post([=](){onFinish.call();}); } -void FluHttp::onError(const QJSValue& callable,int status,QString errorString){ +void FluHttp::onError(const QJSValue& callable,int status,QString errorString,QString result){ QJSValue onError = callable.property("onError"); QJSValueList args; - args<(sent); + args<(total); + QJSValue onUploadProgress = callable.property("onUploadProgress"); + MainThread::post([=](){onUploadProgress.call(args);}); +} diff --git a/src/FluHttp.h b/src/FluHttp.h index c19bdfea..c003c848 100644 --- a/src/FluHttp.h +++ b/src/FluHttp.h @@ -20,18 +20,20 @@ private: void addHeaders(QNetworkRequest* request,const QMap& params); void onStart(const QJSValue& callable); void onFinish(const QJSValue& callable); - void onError(const QJSValue& callable,int status,QString errorString); + void onError(const QJSValue& callable,int status,QString errorString,QString result); void onSuccess(const QJSValue& callable,QString result); void onDownloadProgress(const QJSValue& callable,qint64 recv, qint64 total); + void onUploadProgress(const QJSValue& callable,qint64 recv, qint64 total); public: explicit FluHttp(QObject *parent = nullptr); ~FluHttp(); //神坑!!! 如果参数使用QVariantMap会有问题,在6.4.3版本中QML一调用就会编译失败。所以改用QMap - Q_INVOKABLE void get(QString url,QJSValue callable,QMap = {},QMap headers = {}); - Q_INVOKABLE void post(QString url,QJSValue callable,QMap = {},QMap headers = {}); + Q_INVOKABLE void get(QString url,QJSValue callable,QMap params= {},QMap headers = {}); + Q_INVOKABLE void post(QString url,QJSValue callable,QMap params= {},QMap headers = {}); Q_INVOKABLE void postString(QString url,QJSValue callable,QString params = "",QMap headers = {}); Q_INVOKABLE void postJson(QString url,QJSValue callable,QMap params = {},QMap headers = {}); Q_INVOKABLE void download(QString url,QJSValue callable,QString filePath,QMap params = {},QMap headers = {}); + Q_INVOKABLE void upload(QString url,QJSValue callable,QMap params = {},QMap headers = {}); Q_INVOKABLE void cancel(); private: QList> _cache; diff --git a/src/FluTools.cpp b/src/FluTools.cpp index 1e15d549..3656e877 100644 --- a/src/FluTools.cpp +++ b/src/FluTools.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include FluTools* FluTools::m_instance = nullptr; @@ -100,6 +101,10 @@ QString FluTools::toLocalPath(const QUrl& url){ return url.toLocalFile(); } +QString FluTools::getFileNameByUrl(const QUrl& url){ + return QFileInfo(url.toLocalFile()).fileName(); +} + QString FluTools::html2PlantText(const QString& html){ QTextDocument textDocument; textDocument.setHtml(html); diff --git a/src/FluTools.h b/src/FluTools.h index e887de7e..c4782180 100644 --- a/src/FluTools.h +++ b/src/FluTools.h @@ -103,6 +103,8 @@ public: */ Q_INVOKABLE QString toLocalPath(const QUrl& url); + Q_INVOKABLE QString getFileNameByUrl(const QUrl& url); + /** * @brief deleteItem 销毁Item对象 * @param p