diff --git a/src/Def.h b/src/Def.h index a77e8fd2..812adb82 100644 --- a/src/Def.h +++ b/src/Def.h @@ -4,6 +4,24 @@ #include #include +namespace FluHttpType { +Q_NAMESPACE +enum CacheMode { + /** 不使用缓存 */ + NoCache = 0x0000, + + /** 请求网络失败后,读取缓存 */ + RequestFailedReadCache = 0x0001, + + /** 如果缓存不存在才请求网络,否则使用缓存 */ + IfNoneCacheRequest = 0x0002, + + /** 先使用缓存,不管是否存在,仍然请求网络 */ + FirstCacheThenRequest = 0x0004, +}; +Q_ENUM_NS(CacheMode) +QML_NAMED_ELEMENT(FluHttpType) +} namespace FluScreenshotType { Q_NAMESPACE diff --git a/src/FluHttp.cpp b/src/FluHttp.cpp index 7ada2796..2f9a8fda 100644 --- a/src/FluHttp.cpp +++ b/src/FluHttp.cpp @@ -6,14 +6,20 @@ #include #include #include +#include +#include +#include "Def.h" #include "MainThread.h" #include "FluApp.h" +#include "FluTools.h" FluHttp::FluHttp(QObject *parent) : QObject{parent} { retry(3); timeout(15000); + cacheMode(FluHttpType::CacheMode::RequestFailedReadCache); + cacheDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)+"/httpcache"); } FluHttp::~FluHttp(){ @@ -21,7 +27,7 @@ FluHttp::~FluHttp(){ } void FluHttp::cancel(){ - foreach (QPointer item, _cache) { + foreach (QPointer item, _cacheReply) { if(item){ item->abort(); } @@ -29,11 +35,12 @@ void FluHttp::cancel(){ } void FluHttp::handleReply(QNetworkReply* reply){ - _cache.append(reply); + _cacheReply.append(reply); } void FluHttp::post(QString url,QJSValue callable,QMap params,QMap headers){ - QMap data = invokeIntercept(params,headers,"post").toMap(); + auto requestMap = toRequest(url,params,headers,"post"); + QMap data = invokeIntercept(requestMap).toMap(); QThreadPool::globalInstance()->start([=](){ onStart(callable); for (int i = 0; i < retry(); ++i) { @@ -55,7 +62,7 @@ void FluHttp::post(QString url,QJSValue callable,QMap params, } QEventLoop loop; QNetworkReply* reply = manager.post(request,&multiPart); - _cache.append(reply); + _cacheReply.append(reply); connect(&manager,&QNetworkAccessManager::finished,this,[&loop](QNetworkReply *reply){ loop.quit(); }); @@ -64,10 +71,11 @@ void FluHttp::post(QString url,QJSValue callable,QMap params, int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); QString errorString = reply->errorString(); bool isSuccess = reply->error() == QNetworkReply::NoError; - _cache.removeOne(reply); + _cacheReply.removeOne(reply); reply->deleteLater(); reply = nullptr; if (isSuccess) { + handleCache(requestMap,result); onSuccess(callable,result); break; }else{ @@ -81,7 +89,8 @@ void FluHttp::post(QString url,QJSValue callable,QMap params, } void FluHttp::postString(QString url,QJSValue callable,QString params,QMap headers){ - QMap data = invokeIntercept(params,headers,"postString").toMap(); + auto requestMap = toRequest(url,params,headers,"post"); + QMap data = invokeIntercept(requestMap).toMap(); QThreadPool::globalInstance()->start([=](){ onStart(callable); for (int i = 0; i < retry(); ++i) { @@ -94,7 +103,7 @@ void FluHttp::postString(QString url,QJSValue callable,QString params,QMapattribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); QString errorString = reply->errorString(); bool isSuccess = reply->error() == QNetworkReply::NoError; - _cache.removeOne(reply); + _cacheReply.removeOne(reply); reply->deleteLater(); reply = nullptr; if (isSuccess) { + handleCache(requestMap,result); onSuccess(callable,result); break; }else{ @@ -120,7 +130,8 @@ void FluHttp::postString(QString url,QJSValue callable,QString params,QMap params,QMap headers){ - QMap data = invokeIntercept(params,headers,"postJson").toMap(); + auto requestMap = toRequest(url,params,headers,"post"); + QMap data = invokeIntercept(requestMap).toMap(); QThreadPool::globalInstance()->start([=](){ onStart(callable); for (int i = 0; i < retry(); ++i) { @@ -133,7 +144,7 @@ void FluHttp::postJson(QString url,QJSValue callable,QMap par request.setHeader(QNetworkRequest::ContentTypeHeader, contentType); QEventLoop loop; QNetworkReply* reply = manager.post(request,QJsonDocument::fromVariant(data["params"]).toJson()); - _cache.append(reply); + _cacheReply.append(reply); connect(&manager,&QNetworkAccessManager::finished,this,[&loop](QNetworkReply *reply){ loop.quit(); }); @@ -142,10 +153,11 @@ void FluHttp::postJson(QString url,QJSValue callable,QMap par int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); QString errorString = reply->errorString(); bool isSuccess = reply->error() == QNetworkReply::NoError; - _cache.removeOne(reply); + _cacheReply.removeOne(reply); reply->deleteLater(); reply = nullptr; if (isSuccess) { + handleCache(requestMap,result); onSuccess(callable,result); break; }else{ @@ -159,7 +171,8 @@ void FluHttp::postJson(QString url,QJSValue callable,QMap par } void FluHttp::get(QString url,QJSValue callable,QMap params,QMap headers){ - QMap data = invokeIntercept(params,headers,"get").toMap(); + auto requestMap = toRequest(url,params,headers,"post"); + QMap data = invokeIntercept(requestMap).toMap(); QThreadPool::globalInstance()->start([=](){ for (int i = 0; i < retry(); ++i) { onStart(callable); @@ -171,7 +184,7 @@ void FluHttp::get(QString url,QJSValue callable,QMap params,Q addHeaders(&request,data["headers"].toMap()); QEventLoop loop; QNetworkReply* reply = manager.get(request); - _cache.append(reply); + _cacheReply.append(reply); connect(&manager,&QNetworkAccessManager::finished,this,[&loop](QNetworkReply *reply){ loop.quit(); }); @@ -180,10 +193,11 @@ void FluHttp::get(QString url,QJSValue callable,QMap params,Q int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); QString errorString = reply->errorString(); bool isSuccess = reply->error() == QNetworkReply::NoError; - _cache.removeOne(reply); + _cacheReply.removeOne(reply); reply->deleteLater(); reply = nullptr; if (isSuccess) { + handleCache(requestMap,result); onSuccess(callable,result); break; }else{ @@ -197,7 +211,8 @@ void FluHttp::get(QString url,QJSValue callable,QMap params,Q } void FluHttp::download(QString url,QJSValue callable,QString filePath,QMap params,QMap headers){ - QMap data = invokeIntercept(params,headers,"download").toMap(); + auto requestMap = toRequest(url,params,headers,"post"); + QMap data = invokeIntercept(requestMap).toMap(); QThreadPool::globalInstance()->start([=](){ onStart(callable); QNetworkAccessManager manager; @@ -218,7 +233,7 @@ void FluHttp::download(QString url,QJSValue callable,QString filePath,QMap reply = manager.get(request); - _cache.append(reply); + _cacheReply.append(reply); connect(reply,&QNetworkReply::downloadProgress,this,[=](qint64 bytesReceived, qint64 bytesTotal){ onDownloadProgress(callable,bytesReceived,bytesTotal); }); @@ -229,7 +244,7 @@ void FluHttp::download(QString url,QJSValue callable,QString filePath,QMapattribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(),reply->errorString(),""); } - _cache.removeOne(reply); + _cacheReply.removeOne(reply); reply->deleteLater(); reply = nullptr; onFinish(callable); @@ -237,7 +252,8 @@ void FluHttp::download(QString url,QJSValue callable,QString filePath,QMap params,QMap headers){ - QMap data = invokeIntercept(params,headers,"upload").toMap(); + auto requestMap = toRequest(url,params,headers,"post"); + QMap data = invokeIntercept(requestMap).toMap(); QThreadPool::globalInstance()->start([=](){ onStart(callable); QNetworkAccessManager manager; @@ -262,7 +278,7 @@ void FluHttp::upload(QString url,QJSValue callable,QMap param } QEventLoop loop; QNetworkReply* reply = manager.post(request,&multiPart); - _cache.append(reply); + _cacheReply.append(reply); connect(&manager,&QNetworkAccessManager::finished,this,[&loop](QNetworkReply *reply){ loop.quit(); }); @@ -274,7 +290,7 @@ void FluHttp::upload(QString url,QJSValue callable,QMap param int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); QString errorString = reply->errorString(); bool isSuccess = reply->error() == QNetworkReply::NoError; - _cache.removeOne(reply); + _cacheReply.removeOne(reply); reply->deleteLater(); reply = nullptr; if (isSuccess) { @@ -286,17 +302,22 @@ void FluHttp::upload(QString url,QJSValue callable,QMap param }); } -QVariant FluHttp::invokeIntercept(const QVariant& params,const QVariant& headers,const QString& method){ - QMap requet = { +QMap FluHttp::toRequest(const QString& url,const QVariant& params,const QVariant& headers,const QString& method){ + QMap request = { + {"url",url}, {"params",params}, {"headers",headers}, - {"method",method} + {"method","upload"} }; + return request; +} + +QVariant FluHttp::invokeIntercept(QMap request){ if(!FluApp::getInstance()->httpInterceptor()){ - return requet; + return request; } QVariant target; - QMetaObject::invokeMethod(FluApp::getInstance()->httpInterceptor(), "onIntercept",Q_RETURN_ARG(QVariant,target),Q_ARG(QVariant, requet)); + QMetaObject::invokeMethod(FluApp::getInstance()->httpInterceptor(), "onIntercept",Q_RETURN_ARG(QVariant,target),Q_ARG(QVariant, request)); return target; } @@ -371,3 +392,22 @@ void FluHttp::onUploadProgress(const QJSValue& callable,qint64 sent, qint64 tota onUploadProgress.call(args); }); } + +void FluHttp::handleCache(QMap request,const QString& result){ + if(_cacheMode==FluHttpType::CacheMode::NoCache){ + return; + } + auto fileName = FluTools::getInstance()->md5(QJsonDocument::fromVariant(QVariant(request)).toJson()); + QDir dir = _cacheDir; + if (!dir.exists(_cacheDir)){ + dir.mkpath(_cacheDir); + } + auto filePath = _cacheDir+"/"+fileName; + QSharedPointer file(new QFile(filePath)); + QIODevice::OpenMode mode = QIODevice::WriteOnly|QIODevice::Truncate; + if (!file->open(mode)) + { + return; + } + file->write(FluTools::getInstance()->toBase64(result).toUtf8()); +} diff --git a/src/FluHttp.h b/src/FluHttp.h index c003c848..dacfc2be 100644 --- a/src/FluHttp.h +++ b/src/FluHttp.h @@ -12,9 +12,12 @@ class FluHttp : public QObject Q_OBJECT Q_PROPERTY_AUTO(int,retry); Q_PROPERTY_AUTO(int,timeout) + Q_PROPERTY_AUTO(int,cacheMode); + Q_PROPERTY_AUTO(QString,cacheDir); QML_NAMED_ELEMENT(FluHttp) private: - QVariant invokeIntercept(const QVariant& params,const QVariant& headers,const QString& method); + QVariant invokeIntercept(QMap request); + QMap toRequest(const QString& url,const QVariant& params,const QVariant& headers,const QString& method); void handleReply(QNetworkReply* reply); void addQueryParam(QUrl* url,const QMap& params); void addHeaders(QNetworkRequest* request,const QMap& params); @@ -24,6 +27,7 @@ private: 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); + void handleCache(QMap request, const QString& result); public: explicit FluHttp(QObject *parent = nullptr); ~FluHttp(); @@ -36,7 +40,7 @@ public: Q_INVOKABLE void upload(QString url,QJSValue callable,QMap params = {},QMap headers = {}); Q_INVOKABLE void cancel(); private: - QList> _cache; + QList> _cacheReply; }; #endif // FLUHTTP_H diff --git a/src/FluTools.cpp b/src/FluTools.cpp index 0decf35d..a09e585c 100644 --- a/src/FluTools.cpp +++ b/src/FluTools.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include FluTools* FluTools::m_instance = nullptr; @@ -128,3 +129,19 @@ QUrl FluTools::getUrlByFilePath(const QString& path){ QColor FluTools::colorAlpha(const QColor& color,qreal alpha){ return QColor(color.red(),color.green(),color.blue(),255*alpha); } + +QString FluTools::md5(QString text) +{ + return QCryptographicHash::hash(text.toUtf8(), QCryptographicHash::Md5).toHex(); +} + +QString FluTools::toBase64(QString text) +{ + return text.toUtf8().toBase64(); +} + +QString FluTools::fromBase64(QString text) +{ + return QByteArray::fromBase64(text.toUtf8()); +} + diff --git a/src/FluTools.h b/src/FluTools.h index 1da83f5a..bb2a525b 100644 --- a/src/FluTools.h +++ b/src/FluTools.h @@ -144,6 +144,27 @@ public: */ Q_INVOKABLE QColor colorAlpha(const QColor&,qreal alpha); + /** + * @brief md5 + * @param text + * @return + */ + QString md5(QString text); + + /** + * @brief toBase64 + * @param text + * @return + */ + QString toBase64(QString text); + + /** + * @brief fromBase64 + * @param text + * @return + */ + QString fromBase64(QString text); + }; #endif // FLUTOOLS_H