diff --git a/example/qml/page/T_Http.qml b/example/qml/page/T_Http.qml index 07804936..6eeff28a 100644 --- a/example/qml/page/T_Http.qml +++ b/example/qml/page/T_Http.qml @@ -26,6 +26,7 @@ FluScrollablePage{ } onError: (status,errorString)=>{ + console.debug(status+"->"+errorString) showError(errorString) } onSuccess: @@ -59,6 +60,7 @@ FluScrollablePage{ FluHttp{ id:http_download url:"http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" +// url:"https://www.w3school.com.cn/example/html5/mov_bbb.mp4" onStart: { btn_download.disabled = true } @@ -94,7 +96,8 @@ FluScrollablePage{ FluButton{ text:"Get请求" onClicked: { - http_get.get({q:"FluentUI"}) + http_download.cancel() +// http_get.get({q:"FluentUI"}) } } FluButton{ diff --git a/src/FluHttp.cpp b/src/FluHttp.cpp index 00c70a98..9cdbf17d 100644 --- a/src/FluHttp.cpp +++ b/src/FluHttp.cpp @@ -9,9 +9,6 @@ using namespace AeaQt; FluHttp::FluHttp(QObject *parent) : QObject{parent} { - enabledBreakpointDownload(false); - timeout(15); - retry(3); } @@ -20,140 +17,193 @@ FluHttp::~FluHttp(){ } void FluHttp::cancel(){ - foreach (auto item, cache) { + foreach (QPointer item, _cache) { if(item){ - qDebug()<abort(); } } } void FluHttp::handleReply(QNetworkReply* reply){ - cache.append(reply); + _cache.append(reply); } void FluHttp::postString(QString params,QVariantMap headers){ - QVariantMap request = invokeIntercept(params,headers,"postString").toMap(); + QVariantMap data = invokeIntercept(params,headers,"postString").toMap(); QThreadPool::globalInstance()->start([=](){ Q_EMIT start(); - HttpClient client; - client.initReplyCompleted = [=](QNetworkReply* reply){ handleReply(reply); }; - client.post(_url) - .retry(retry()) - .timeout(timeout()) - .bodyWithRaw(request[params].toString().toUtf8()) - .headers(request["headers"].toMap()) - .onSuccess([=](QString result) { - Q_EMIT success(result); - }) - .onFailed([=](QNetworkReply* reply) { - Q_EMIT error(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(),reply->errorString()); - }) - .block() - .exec(); + QNetworkAccessManager manager; + QUrl url(_url); + QNetworkRequest request(url); + addHeaders(&request,data["headers"].toMap()); + QHttpMultiPart* multiPart = new QHttpMultiPart(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; + const QString& value = each.second.toString(); + QString dispositionHeader = QString("form-data; name=\"%1\"").arg(key); + QHttpPart part; + part.setHeader(QNetworkRequest::ContentDispositionHeader, dispositionHeader); + part.setBody(value.toUtf8()); + multiPart->append(part); + } + QEventLoop loop; + QNetworkReply* reply = manager.post(request,multiPart); + connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); + loop.exec(); + if (reply->error() == QNetworkReply::NoError) { + Q_EMIT success(QString::fromUtf8(reply->readAll())); + }else{ + Q_EMIT error(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(),reply->errorString()); + } + reply->deleteLater(); + reply = nullptr; Q_EMIT finish(); }); } void FluHttp::post(QVariantMap params,QVariantMap headers){ - QVariantMap request = invokeIntercept(params,headers,"post").toMap(); + QVariantMap data = invokeIntercept(params,headers,"post").toMap(); QThreadPool::globalInstance()->start([=](){ Q_EMIT start(); - HttpClient client; - client.initReplyCompleted = [=](QNetworkReply* reply){ handleReply(reply); }; - client.post(_url) - .retry(retry()) - .timeout(timeout()) - .headers(headers) - .bodyWithFormData(request["params"].toMap()) - .headers(request["headers"].toMap()) - .onSuccess([=](QString result) { - Q_EMIT success(result); - }) - .onFailed([=](QNetworkReply* reply) { - Q_EMIT error(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(),reply->errorString()); - }) - .block() - .exec(); + QNetworkAccessManager manager; + QUrl url(_url); + QNetworkRequest request(url); + addHeaders(&request,data["headers"].toMap()); + QHttpMultiPart* multiPart = new QHttpMultiPart(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; + const QString& value = each.second.toString(); + QString dispositionHeader = QString("form-data; name=\"%1\"").arg(key); + QHttpPart part; + part.setHeader(QNetworkRequest::ContentDispositionHeader, dispositionHeader); + part.setBody(value.toUtf8()); + multiPart->append(part); + } + QEventLoop loop; + QNetworkReply* reply = manager.post(request,multiPart); + connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); + loop.exec(); + if (reply->error() == QNetworkReply::NoError) { + Q_EMIT success(QString::fromUtf8(reply->readAll())); + }else{ + Q_EMIT error(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(),reply->errorString()); + } + reply->deleteLater(); + reply = nullptr; Q_EMIT finish(); }); } void FluHttp::postJson(QVariantMap params,QVariantMap headers){ - QVariantMap request = invokeIntercept(params,headers,"postJson").toMap(); + QVariantMap data = invokeIntercept(params,headers,"postJson").toMap(); QThreadPool::globalInstance()->start([=](){ Q_EMIT start(); - HttpClient client; - client.initReplyCompleted = [=](QNetworkReply* reply){ handleReply(reply); }; - client.post(_url) - .retry(retry()) - .timeout(timeout()) - .headers(headers) - .bodyWithRaw(QJsonDocument::fromVariant(request["params"]).toJson()) - .headers(request["headers"].toMap()) - .onSuccess([=](QString result) { - Q_EMIT success(result); - }) - .onFailed([=](QNetworkReply* reply) { - Q_EMIT error(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(),reply->errorString()); - }) - .block() - .exec(); + QNetworkAccessManager manager; + QUrl url(_url); + QNetworkRequest request(url); + addHeaders(&request,data["headers"].toMap()); + QHttpMultiPart* multiPart = new QHttpMultiPart(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; + const QString& value = each.second.toString(); + QString dispositionHeader = QString("form-data; name=\"%1\"").arg(key); + QHttpPart part; + part.setHeader(QNetworkRequest::ContentDispositionHeader, dispositionHeader); + part.setBody(value.toUtf8()); + multiPart->append(part); + } + QEventLoop loop; + QNetworkReply* reply = manager.post(request,multiPart); + connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); + loop.exec(); + if (reply->error() == QNetworkReply::NoError) { + Q_EMIT success(QString::fromUtf8(reply->readAll())); + }else{ + Q_EMIT error(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(),reply->errorString()); + } + reply->deleteLater(); + reply = nullptr; Q_EMIT finish(); }); } void FluHttp::get(QVariantMap params,QVariantMap headers){ - QVariantMap request = invokeIntercept(params,headers,"get").toMap(); + QVariantMap data = invokeIntercept(params,headers,"get").toMap(); QThreadPool::globalInstance()->start([=](){ Q_EMIT start(); - HttpClient client; - client.initReplyCompleted = [=](QNetworkReply* reply){ handleReply(reply); }; - client.get(_url) - .retry(retry()) - .timeout(timeout()) - .queryParams(request["params"].toMap()) - .headers(request["headers"].toMap()) - .onSuccess([=](QString result) { - Q_EMIT success(result); - }) - .onFailed([=](QNetworkReply* reply) { - Q_EMIT error(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(),reply->errorString()); - }) - .block() - .exec(); + QNetworkAccessManager manager; + QUrl url(_url); + addQueryParam(&url,data["params"].toMap()); + QNetworkRequest request(url); + addHeaders(&request,data["headers"].toMap()); + QEventLoop loop; + QNetworkReply* reply = manager.get(request); + connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); + loop.exec(); + if (reply->error() == QNetworkReply::NoError) { + Q_EMIT success(QString::fromUtf8(reply->readAll())); + }else{ + Q_EMIT error(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(),reply->errorString()); + } + reply->deleteLater(); + reply = nullptr; Q_EMIT finish(); }); } void FluHttp::download(QString path,QVariantMap params,QVariantMap headers){ - QPointer weakThis(this); - QVariantMap request = invokeIntercept(params,headers,"download").toMap(); + QVariantMap data = invokeIntercept(params,headers,"download").toMap(); QThreadPool::globalInstance()->start([=](){ Q_EMIT start(); - HttpClient client; - client.initReplyCompleted = [=](QNetworkReply* reply){ handleReply(reply); }; - client.get(_url) - .retry(retry()) - .timeout(timeout()) - .download(path) - .enabledBreakpointDownload(_enabledBreakpointDownload) - .queryParams(request["params"].toMap()) - .headers(request["headers"].toMap()) - .onDownloadProgress([=](qint64 recv, qint64 total) { - if (!weakThis) { - return; - } - Q_EMIT weakThis->downloadProgress(recv,total); - }) - .onDownloadFileSuccess([=](QString result) { - Q_EMIT success(result); - }) - .onDownloadFileFailed([=](QString errorString) { - Q_EMIT error(-1,errorString); - }) - .block() - .exec(); + QNetworkAccessManager manager; + QUrl url(_url); + addQueryParam(&url,data["params"].toMap()); + QNetworkRequest request(url); + addHeaders(&request,data["headers"].toMap()); + QFile *file = new QFile(path); + QIODevice::OpenMode mode = QIODevice::WriteOnly|QIODevice::Truncate; + if (!file->open(mode)) + { + Q_EMIT error(-1,QString("Url: %1 %2 Non-Writable").arg(request.url().toString(),file->fileName())); + file->deleteLater(); + file = nullptr; + Q_EMIT finish(); + return; + } + QEventLoop *loop = new QEventLoop(); + connect(&manager,&QNetworkAccessManager::finished,this,[=](QNetworkReply *reply){ + loop->quit(); + }); + QPointer reply = manager.get(request); + _cache.append(reply); + connect(reply,&QNetworkReply::downloadProgress,this,[=](qint64 bytesReceived, qint64 bytesTotal){ + Q_EMIT downloadProgress(bytesReceived,bytesTotal); + }); + connect(reply,&QNetworkReply::readyRead,this,[=](){ + file->write(reply->readAll()); + }); + loop->exec(); + if (reply->error() == QNetworkReply::NoError) { + Q_EMIT success(path); + }else{ + Q_EMIT error(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(),reply->errorString()); + } + file->close(); + loop->deleteLater(); + file->deleteLater(); + reply->deleteLater(); + loop = nullptr; + file = nullptr; + reply = nullptr; Q_EMIT finish(); }); } @@ -171,3 +221,23 @@ QVariant FluHttp::invokeIntercept(const QVariant& params,const QVariant& headers QMetaObject::invokeMethod(FluApp::getInstance()->httpInterceptor(), "onIntercept",Q_RETURN_ARG(QVariant,target),Q_ARG(QVariant, requet)); return target; } + +void FluHttp::addQueryParam(QUrl* url,const QMap& params){ + QMapIterator iter(params); + QUrlQuery urlQuery(*url); + while (iter.hasNext()) + { + iter.next(); + urlQuery.addQueryItem(iter.key(), iter.value().toString()); + } + url->setQuery(urlQuery); +} + +void FluHttp::addHeaders(QNetworkRequest* request,const QMap& headers){ + QMapIterator iter(headers); + while (iter.hasNext()) + { + iter.next(); + request->setRawHeader(iter.key().toUtf8(), iter.value().toString().toUtf8()); + } +} diff --git a/src/FluHttp.h b/src/FluHttp.h index dc774f80..d2709924 100644 --- a/src/FluHttp.h +++ b/src/FluHttp.h @@ -3,6 +3,7 @@ #include #include +#include #include #include "stdafx.h" @@ -10,14 +11,12 @@ class FluHttp : public QObject { Q_OBJECT Q_PROPERTY_AUTO(QString,url); - Q_PROPERTY_AUTO(bool,enabledBreakpointDownload) - Q_PROPERTY_AUTO(int,timeout) - Q_PROPERTY_AUTO(int,retry); QML_NAMED_ELEMENT(FluHttp) private: QVariant invokeIntercept(const QVariant& params,const QVariant& headers,const QString& method); void handleReply(QNetworkReply* reply); - QList cache; + void addQueryParam(QUrl* url,const QMap& params); + void addHeaders(QNetworkRequest* request,const QMap& params); public: explicit FluHttp(QObject *parent = nullptr); ~FluHttp(); @@ -32,6 +31,8 @@ public: Q_INVOKABLE void postString(QString params = "",QVariantMap headers = {}); Q_INVOKABLE void download(QString path,QVariantMap params = {},QVariantMap headers = {}); Q_INVOKABLE void cancel(); +private: + QList> _cache; }; #endif // FLUHTTP_H