|
|
@@ -1,5 +1,4 @@
|
|
|
#include "networkaccessmanager.h"
|
|
|
-
|
|
|
#include "appevent.h"
|
|
|
|
|
|
#include <QBuffer>
|
|
|
@@ -9,12 +8,11 @@
|
|
|
#include <QJsonDocument>
|
|
|
#include <QJsonObject>
|
|
|
#include <QUrlQuery>
|
|
|
+#include <QtConcurrent>
|
|
|
|
|
|
// 基础URL配置
|
|
|
static QString base_url("http://127.0.0.1:8200");
|
|
|
-
|
|
|
static const QString messageVal = "msg";
|
|
|
-// static QString base_url("http://127.0.0.1:8888/api");
|
|
|
|
|
|
static NetworkAccessManager* namInstance = nullptr;
|
|
|
|
|
|
@@ -121,453 +119,328 @@ QNetworkReply* NetworkAccessManager::createRequest(Operation op,
|
|
|
}
|
|
|
|
|
|
namespace TC {
|
|
|
-// 认证请求拦截器
|
|
|
-class AuthRequestInterceptor : public Interceptor
|
|
|
-{
|
|
|
-public:
|
|
|
- void interceptRequest(QNetworkRequest& request) override;
|
|
|
-};
|
|
|
-
|
|
|
-// 认证响应拦截器
|
|
|
-class AuthResponseInterceptor : public Interceptor
|
|
|
-{
|
|
|
-public:
|
|
|
- void interceptResponse(QNetworkReply* reply) override;
|
|
|
-
|
|
|
-private:
|
|
|
- void doRefreshToken();
|
|
|
- void doReAuthenticate();
|
|
|
-};
|
|
|
-// 错误响应拦截器
|
|
|
-class ErrorResponseInterceptor : public Interceptor
|
|
|
-{
|
|
|
-public:
|
|
|
- void interceptResponse(QNetworkReply* reply) override;
|
|
|
-};
|
|
|
-
|
|
|
-// 请求客户端实现
|
|
|
RequestClient::RequestClient(const RequestClientOptions& options)
|
|
|
: m_baseUrl(options.baseURL)
|
|
|
+ , m_timeout(options.timeout)
|
|
|
+ , m_networkManager(NetworkAccessManager::instance())
|
|
|
{
|
|
|
- // 初始化默认拦截器
|
|
|
if (options.enableDefaultInterceptors) {
|
|
|
setupDefaultInterceptors();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-RequestClient* RequestClient::createClient(const QString& baseURL,
|
|
|
- const RequestClientOptions& options)
|
|
|
+RequestClient::Ptr RequestClient::create(const QString& baseURL, const RequestClientOptions& options)
|
|
|
{
|
|
|
RequestClientOptions opts = options;
|
|
|
opts.baseURL = baseURL;
|
|
|
- return new RequestClient(opts);
|
|
|
+ return Ptr(new RequestClient(opts));
|
|
|
}
|
|
|
|
|
|
-void RequestClient::setupDefaultInterceptors()
|
|
|
+RequestClient::Ptr RequestClient::globalInstance()
|
|
|
{
|
|
|
- // 添加认证拦截器
|
|
|
- auto authRequestInterceptor = new AuthRequestInterceptor();
|
|
|
- addInterceptor(authRequestInterceptor);
|
|
|
-
|
|
|
- // 添加响应拦截器
|
|
|
- auto authResponseInterceptor = new AuthResponseInterceptor();
|
|
|
- addInterceptor(authResponseInterceptor);
|
|
|
-
|
|
|
- // 添加错误处理拦截器
|
|
|
- auto errorInterceptor = new ErrorResponseInterceptor();
|
|
|
- addInterceptor(errorInterceptor);
|
|
|
+ static RequestClient::Ptr instance = create(base_url, {"", true});
|
|
|
+ return instance;
|
|
|
}
|
|
|
|
|
|
-void RequestClient::addInterceptor(Interceptor* interceptor)
|
|
|
+RequestClient::Ptr RequestClient::baseGlobalInstance()
|
|
|
{
|
|
|
- if (!interceptors.contains(interceptor)) {
|
|
|
- interceptors.append(interceptor);
|
|
|
- }
|
|
|
+ static RequestClient::Ptr instance = create(base_url, {"", false});
|
|
|
+ return instance;
|
|
|
}
|
|
|
|
|
|
-void RequestClient::removeInterceptor(Interceptor* interceptor)
|
|
|
+void RequestClient::setupDefaultInterceptors()
|
|
|
{
|
|
|
- interceptors.removeOne(interceptor);
|
|
|
-}
|
|
|
+ QMutexLocker locker(&m_interceptorMutex);
|
|
|
|
|
|
-void RequestClient::setBaseUrl(const QString& url)
|
|
|
-{
|
|
|
- m_baseUrl = url;
|
|
|
+ // 添加认证拦截器
|
|
|
+ m_interceptors.push_back(std::make_shared<AuthRequestInterceptor>());
|
|
|
+
|
|
|
+ // 添加错误处理拦截器
|
|
|
+ m_interceptors.push_back(std::make_shared<ErrorResponseInterceptor>());
|
|
|
}
|
|
|
|
|
|
-QString RequestClient::baseUrl() const
|
|
|
+void RequestClient::addInterceptor(std::shared_ptr<Interceptor> interceptor)
|
|
|
{
|
|
|
- if (m_baseUrl.isEmpty()) {
|
|
|
- return base_url;
|
|
|
+ QMutexLocker locker(&m_interceptorMutex);
|
|
|
+ if (!m_interceptors.contains(interceptor)) {
|
|
|
+ m_interceptors.append(interceptor);
|
|
|
}
|
|
|
- return m_baseUrl;
|
|
|
}
|
|
|
|
|
|
-void RequestClient::setTimeout(int timeout)
|
|
|
+void RequestClient::removeInterceptor(std::shared_ptr<Interceptor> interceptor)
|
|
|
{
|
|
|
- m_timeout = timeout;
|
|
|
+ QMutexLocker locker(&m_interceptorMutex);
|
|
|
+ m_interceptors.removeOne(interceptor);
|
|
|
}
|
|
|
|
|
|
-int RequestClient::timeout() const
|
|
|
+void RequestClient::clearInterceptors()
|
|
|
{
|
|
|
- return m_timeout;
|
|
|
+ QMutexLocker locker(&m_interceptorMutex);
|
|
|
+ m_interceptors.clear();
|
|
|
}
|
|
|
|
|
|
-QNetworkReply* RequestClient::getSync(const QString& url, const QVariantMap& params)
|
|
|
+HttpResponse RequestClient::get(const QString& url, const QVariantMap& params)
|
|
|
{
|
|
|
- QNetworkReply* reply = get(url, params);
|
|
|
+ QScopedPointer<QNetworkReply> reply(sendGetRequest(url, params));
|
|
|
|
|
|
- // 同步等待
|
|
|
QEventLoop loop;
|
|
|
- QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
|
|
+ QObject::connect(reply.get(), &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
|
|
loop.exec();
|
|
|
|
|
|
- // 处理响应拦截器
|
|
|
- processResponse(reply);
|
|
|
-
|
|
|
- return reply;
|
|
|
+ return parseReplyData(reply.get());
|
|
|
}
|
|
|
|
|
|
-QNetworkReply* RequestClient::postSync(const QString& url, const QJsonDocument& data)
|
|
|
+HttpResponse RequestClient::post(const QString& url, const QJsonDocument& data)
|
|
|
{
|
|
|
- QNetworkReply* reply = post(url, data);
|
|
|
+ QScopedPointer<QNetworkReply> reply(sendPostRequest(url, data));
|
|
|
|
|
|
- // 同步等待
|
|
|
QEventLoop loop;
|
|
|
- QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
|
|
+ QObject::connect(reply.get(), &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
|
|
loop.exec();
|
|
|
|
|
|
- // 处理响应拦截器
|
|
|
- processResponse(reply);
|
|
|
-
|
|
|
- return reply;
|
|
|
+ return parseReplyData(reply.get());
|
|
|
}
|
|
|
|
|
|
-QNetworkReply* RequestClient::putSync(const QString& url, const QJsonDocument& data)
|
|
|
+HttpResponse RequestClient::put(const QString& url, const QJsonDocument& data)
|
|
|
{
|
|
|
- QNetworkReply* reply = put(url, data);
|
|
|
+ QScopedPointer<QNetworkReply> reply(sendPutRequest(url, data));
|
|
|
|
|
|
- // 同步等待
|
|
|
QEventLoop loop;
|
|
|
- QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
|
|
+ QObject::connect(reply.get(), &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
|
|
loop.exec();
|
|
|
|
|
|
- // 处理响应拦截器
|
|
|
- processResponse(reply);
|
|
|
-
|
|
|
- return reply;
|
|
|
+ return parseReplyData(reply.get());
|
|
|
}
|
|
|
|
|
|
-QNetworkReply* RequestClient::deleteSync(const QString& url)
|
|
|
+HttpResponse RequestClient::deleteResource(const QString& url)
|
|
|
{
|
|
|
- QNetworkReply* reply = deleteResource(url);
|
|
|
+ QScopedPointer<QNetworkReply> reply(sendDeleteRequest(url));
|
|
|
|
|
|
- // 同步等待
|
|
|
QEventLoop loop;
|
|
|
- QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
|
|
+ QObject::connect(reply.get(), &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
|
|
loop.exec();
|
|
|
|
|
|
- // 处理响应拦截器
|
|
|
- processResponse(reply);
|
|
|
-
|
|
|
- return reply;
|
|
|
+ return parseReplyData(reply.get());
|
|
|
}
|
|
|
|
|
|
-QNetworkReply* RequestClient::uploadSync(const QString& url, QHttpMultiPart* multiPart)
|
|
|
+HttpResponse RequestClient::upload(const QString& url, QHttpMultiPart* multiPart)
|
|
|
{
|
|
|
- QNetworkReply* reply = upload(url, multiPart);
|
|
|
+ QScopedPointer<QNetworkReply> reply(sendUploadRequest(url, multiPart));
|
|
|
|
|
|
- // 同步等待
|
|
|
QEventLoop loop;
|
|
|
- QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
|
|
+ QObject::connect(reply.get(), &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
|
|
loop.exec();
|
|
|
|
|
|
- // 处理响应拦截器
|
|
|
- processResponse(reply);
|
|
|
-
|
|
|
- return reply;
|
|
|
+ return parseReplyData(reply.get());
|
|
|
}
|
|
|
|
|
|
QFuture<HttpResponse> RequestClient::getAsync(const QString& url, const QVariantMap& params)
|
|
|
{
|
|
|
- QFutureInterface<HttpResponse> interface;
|
|
|
- interface.reportStarted();
|
|
|
-
|
|
|
- QNetworkReply* reply = get(url, params);
|
|
|
- setupAsyncConnections(reply, interface);
|
|
|
-
|
|
|
- return interface.future();
|
|
|
+ return QtConcurrent::run([this, url, params] { return get(url, params); });
|
|
|
}
|
|
|
|
|
|
QFuture<HttpResponse> RequestClient::postAsync(const QString& url, const QJsonDocument& data)
|
|
|
{
|
|
|
- QFutureInterface<HttpResponse> interface;
|
|
|
- interface.reportStarted();
|
|
|
-
|
|
|
- QNetworkReply* reply = post(url, data);
|
|
|
- setupAsyncConnections(reply, interface);
|
|
|
-
|
|
|
- return interface.future();
|
|
|
+ return QtConcurrent::run([this, url, data] { return post(url, data); });
|
|
|
}
|
|
|
|
|
|
QFuture<HttpResponse> RequestClient::putAsync(const QString& url, const QJsonDocument& data)
|
|
|
{
|
|
|
- QFutureInterface<HttpResponse> interface;
|
|
|
- interface.reportStarted();
|
|
|
-
|
|
|
- QNetworkReply* reply = put(url, data);
|
|
|
- setupAsyncConnections(reply, interface);
|
|
|
-
|
|
|
- return interface.future();
|
|
|
+ return QtConcurrent::run([this, url, data] { return put(url, data); });
|
|
|
}
|
|
|
|
|
|
QFuture<HttpResponse> RequestClient::deleteAsync(const QString& url)
|
|
|
{
|
|
|
- QFutureInterface<HttpResponse> interface;
|
|
|
- interface.reportStarted();
|
|
|
-
|
|
|
- QNetworkReply* reply = deleteResource(url);
|
|
|
- setupAsyncConnections(reply, interface);
|
|
|
-
|
|
|
- return interface.future();
|
|
|
+ return QtConcurrent::run([this, url] { return deleteResource(url); });
|
|
|
}
|
|
|
|
|
|
QFuture<HttpResponse> RequestClient::uploadAsync(const QString& url, QHttpMultiPart* multiPart)
|
|
|
{
|
|
|
- QFutureInterface<HttpResponse> interface;
|
|
|
- interface.reportStarted();
|
|
|
-
|
|
|
- QNetworkReply* reply = upload(url, multiPart);
|
|
|
- setupAsyncConnections(reply, interface);
|
|
|
-
|
|
|
- return interface.future();
|
|
|
+ return QtConcurrent::run([this, url, multiPart] { return upload(url, multiPart); });
|
|
|
}
|
|
|
|
|
|
-HttpResponse RequestClient::parseReplyData(QNetworkReply* reply)
|
|
|
+bool RequestClient::download(const QString& url, const QString& saveFilePath)
|
|
|
{
|
|
|
- HttpResponse response;
|
|
|
+ QScopedPointer<QNetworkReply> reply(sendGetRequest(url, {}));
|
|
|
|
|
|
- if (reply->error() != QNetworkReply::NoError) {
|
|
|
- response.code = reply->error();
|
|
|
- response.message = reply->errorString();
|
|
|
- return response;
|
|
|
+ QFile file(saveFilePath);
|
|
|
+ if (!file.open(QIODevice::WriteOnly)) {
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
- const QByteArray responseData = reply->readAll();
|
|
|
- QJsonDocument jsonDoc = QJsonDocument::fromJson(responseData);
|
|
|
- qDebug() << responseData << jsonDoc;
|
|
|
- if (jsonDoc.isObject()) {
|
|
|
- const QJsonObject jsonObj = jsonDoc.object();
|
|
|
- qDebug() << jsonObj;
|
|
|
- if (jsonObj.contains("code")) {
|
|
|
- response.code = jsonObj["code"].toInt();
|
|
|
- }
|
|
|
- if (jsonObj.contains(messageVal)) {
|
|
|
- response.message = jsonObj[messageVal].toString();
|
|
|
- }
|
|
|
- if (jsonObj.contains("data")) {
|
|
|
- QJsonValue dataValue = jsonObj["data"];
|
|
|
- response.data = dataValue;
|
|
|
- }
|
|
|
- }
|
|
|
+ QEventLoop loop;
|
|
|
+ QObject::connect(reply.get(), &QNetworkReply::readyRead, [&]() {
|
|
|
+ file.write(reply->readAll());
|
|
|
+ });
|
|
|
|
|
|
- return response;
|
|
|
-}
|
|
|
+ QObject::connect(reply.get(), &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
|
|
+ loop.exec();
|
|
|
|
|
|
-void RequestClient::processRequest(QNetworkRequest& request)
|
|
|
-{
|
|
|
- for (auto interceptor : interceptors) {
|
|
|
- interceptor->interceptRequest(request);
|
|
|
- }
|
|
|
+ file.close();
|
|
|
+ return reply->error() == QNetworkReply::NoError;
|
|
|
}
|
|
|
|
|
|
-void RequestClient::processResponse(QNetworkReply* reply)
|
|
|
+QFuture<bool> RequestClient::downloadAsync(const QString& url, const QString& saveFilePath)
|
|
|
{
|
|
|
- for (auto interceptor : interceptors) {
|
|
|
- interceptor->interceptResponse(reply);
|
|
|
- }
|
|
|
+ return QtConcurrent::run([this, url, saveFilePath] { return download(url, saveFilePath); });
|
|
|
}
|
|
|
|
|
|
-QNetworkReply* RequestClient::get(const QString& url, const QVariantMap& params)
|
|
|
+QNetworkReply* RequestClient::sendGetRequest(const QString& url, const QVariantMap& params)
|
|
|
{
|
|
|
- QNetworkAccessManager* manager = NetworkAccessManager::instance();
|
|
|
- manager->setTransferTimeout(m_timeout);
|
|
|
-
|
|
|
- QUrl fullUrl(m_baseUrl.isEmpty() ? QString(base_url).append(url) : m_baseUrl.append(url));
|
|
|
+ m_networkManager->setTransferTimeout(m_timeout);
|
|
|
|
|
|
- QUrlQuery query;
|
|
|
- for (auto it = params.constBegin(); it != params.constEnd(); ++it) {
|
|
|
- query.addQueryItem(it.key(), it.value().toString());
|
|
|
- }
|
|
|
+ QString base = m_baseUrl.isEmpty() ? base_url : m_baseUrl;
|
|
|
+ QUrl fullUrl(base + url);
|
|
|
|
|
|
if (!params.isEmpty()) {
|
|
|
+ QUrlQuery query;
|
|
|
+ for (auto it = params.constBegin(); it != params.constEnd(); ++it) {
|
|
|
+ query.addQueryItem(it.key(), it.value().toString());
|
|
|
+ }
|
|
|
fullUrl.setQuery(query);
|
|
|
}
|
|
|
|
|
|
- QNetworkRequest modifiedRequest(fullUrl);
|
|
|
- modifiedRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
|
|
- processRequest(modifiedRequest);
|
|
|
-
|
|
|
- QNetworkReply* reply = manager->get(modifiedRequest);
|
|
|
+ QNetworkRequest request(fullUrl);
|
|
|
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
|
|
+ processRequest(request);
|
|
|
|
|
|
- return reply;
|
|
|
+ emit requestStarted(fullUrl);
|
|
|
+ return m_networkManager->get(request);
|
|
|
}
|
|
|
|
|
|
-QNetworkReply* RequestClient::post(const QString& url, const QJsonDocument& data)
|
|
|
+QNetworkReply* RequestClient::sendPostRequest(const QString& url, const QJsonDocument& data)
|
|
|
{
|
|
|
- QNetworkAccessManager* manager = NetworkAccessManager::instance();
|
|
|
- manager->setTransferTimeout(m_timeout);
|
|
|
+ m_networkManager->setTransferTimeout(m_timeout);
|
|
|
|
|
|
- QUrl fullUrl(m_baseUrl.isEmpty() ? QString(base_url).append(url) : m_baseUrl.append(url));
|
|
|
+ QString base = m_baseUrl.isEmpty() ? base_url : m_baseUrl;
|
|
|
+ QUrl fullUrl(base + url);
|
|
|
|
|
|
QBuffer* buffer = new QBuffer;
|
|
|
buffer->setData(data.toJson());
|
|
|
buffer->open(QIODevice::ReadOnly);
|
|
|
|
|
|
- QNetworkRequest modifiedRequest(fullUrl);
|
|
|
- modifiedRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
|
|
- processRequest(modifiedRequest);
|
|
|
+ QNetworkRequest request(fullUrl);
|
|
|
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
|
|
+ processRequest(request);
|
|
|
|
|
|
- QNetworkReply* reply = manager->post(modifiedRequest, buffer);
|
|
|
+ emit requestStarted(fullUrl);
|
|
|
+ QNetworkReply* reply = m_networkManager->post(request, buffer);
|
|
|
buffer->setParent(reply);
|
|
|
|
|
|
return reply;
|
|
|
}
|
|
|
|
|
|
-QNetworkReply* RequestClient::put(const QString& url, const QJsonDocument& data)
|
|
|
+QNetworkReply* RequestClient::sendPutRequest(const QString& url, const QJsonDocument& data)
|
|
|
{
|
|
|
- QNetworkAccessManager* manager = NetworkAccessManager::instance();
|
|
|
- manager->setTransferTimeout(m_timeout);
|
|
|
+ m_networkManager->setTransferTimeout(m_timeout);
|
|
|
|
|
|
- QUrl fullUrl(m_baseUrl.isEmpty() ? QString(base_url).append(url) : m_baseUrl.append(url));
|
|
|
+ QString base = m_baseUrl.isEmpty() ? base_url : m_baseUrl;
|
|
|
+ QUrl fullUrl(base + url);
|
|
|
|
|
|
QBuffer* buffer = new QBuffer;
|
|
|
buffer->setData(data.toJson());
|
|
|
buffer->open(QIODevice::ReadOnly);
|
|
|
|
|
|
- QNetworkRequest modifiedRequest(fullUrl);
|
|
|
- processRequest(modifiedRequest);
|
|
|
- QNetworkReply* reply = manager->put(modifiedRequest, buffer);
|
|
|
+ QNetworkRequest request(fullUrl);
|
|
|
+ processRequest(request);
|
|
|
+
|
|
|
+ emit requestStarted(fullUrl);
|
|
|
+ QNetworkReply* reply = m_networkManager->put(request, buffer);
|
|
|
buffer->setParent(reply);
|
|
|
|
|
|
return reply;
|
|
|
}
|
|
|
|
|
|
-QNetworkReply* RequestClient::deleteResource(const QString& url)
|
|
|
+QNetworkReply* RequestClient::sendDeleteRequest(const QString& url)
|
|
|
{
|
|
|
- QNetworkAccessManager* manager = NetworkAccessManager::instance();
|
|
|
- manager->setTransferTimeout(m_timeout);
|
|
|
+ m_networkManager->setTransferTimeout(m_timeout);
|
|
|
|
|
|
- QUrl fullUrl(m_baseUrl.isEmpty() ? QString(base_url).append(url) : m_baseUrl.append(url));
|
|
|
+ QString base = m_baseUrl.isEmpty() ? base_url : m_baseUrl;
|
|
|
+ QUrl fullUrl(base + url);
|
|
|
|
|
|
- QNetworkRequest modifiedRequest(fullUrl);
|
|
|
- processRequest(modifiedRequest);
|
|
|
- QNetworkReply* reply = manager->deleteResource(modifiedRequest);
|
|
|
+ QNetworkRequest request(fullUrl);
|
|
|
+ processRequest(request);
|
|
|
|
|
|
- return reply;
|
|
|
+ emit requestStarted(fullUrl);
|
|
|
+ return m_networkManager->deleteResource(request);
|
|
|
}
|
|
|
|
|
|
-QNetworkReply* RequestClient::upload(const QString& url, QHttpMultiPart* multiPart)
|
|
|
+QNetworkReply* RequestClient::sendUploadRequest(const QString& url, QHttpMultiPart* multiPart)
|
|
|
{
|
|
|
- QNetworkAccessManager* manager = NetworkAccessManager::instance();
|
|
|
- manager->setTransferTimeout(m_timeout);
|
|
|
+ m_networkManager->setTransferTimeout(m_timeout);
|
|
|
|
|
|
- QUrl fullUrl(m_baseUrl.isEmpty() ? QString(base_url).append(url) : m_baseUrl.append(url));
|
|
|
+ QString base = m_baseUrl.isEmpty() ? base_url : m_baseUrl;
|
|
|
+ QUrl fullUrl(base + url);
|
|
|
|
|
|
- QNetworkRequest modifiedRequest(fullUrl);
|
|
|
+ QNetworkRequest request(fullUrl);
|
|
|
+ processRequest(request);
|
|
|
|
|
|
- QNetworkReply* reply = manager->post(modifiedRequest, multiPart);
|
|
|
-
|
|
|
- return reply;
|
|
|
+ emit requestStarted(fullUrl);
|
|
|
+ return m_networkManager->post(request, multiPart);
|
|
|
}
|
|
|
|
|
|
-bool RequestClient::download(const QString& url, const QString& saveFilePath)
|
|
|
+HttpResponse RequestClient::parseReplyData(QNetworkReply* reply)
|
|
|
{
|
|
|
- QNetworkReply* reply = get(url);
|
|
|
-
|
|
|
- QEventLoop loop;
|
|
|
- QFile file(saveFilePath);
|
|
|
+ HttpResponse response;
|
|
|
|
|
|
- if (!file.open(QIODevice::WriteOnly)) {
|
|
|
- return false;
|
|
|
+ if (reply->error() != QNetworkReply::NoError) {
|
|
|
+ response.code = reply->error();
|
|
|
+ response.message = reply->errorString();
|
|
|
+ emit requestFailed(reply->url(), response.message);
|
|
|
+ return response;
|
|
|
}
|
|
|
|
|
|
- QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
|
|
- QObject::connect(reply, &QNetworkReply::readyRead, [&]() { file.write(reply->readAll()); });
|
|
|
+ const QByteArray responseData = readReplyData(reply);
|
|
|
+ response.rawData = responseData;
|
|
|
|
|
|
- loop.exec();
|
|
|
+ QJsonDocument jsonDoc = QJsonDocument::fromJson(responseData);
|
|
|
+ if (jsonDoc.isObject()) {
|
|
|
+ const QJsonObject jsonObj = jsonDoc.object();
|
|
|
+ if (jsonObj.contains("code")) {
|
|
|
+ response.code = jsonObj["code"].toInt();
|
|
|
+ }
|
|
|
+ if (jsonObj.contains(messageVal)) {
|
|
|
+ response.message = jsonObj[messageVal].toString();
|
|
|
+ }
|
|
|
+ if (jsonObj.contains("data")) {
|
|
|
+ response.data = jsonObj["data"];
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- file.close();
|
|
|
+ emit requestFinished(reply->url(), response);
|
|
|
+ return response;
|
|
|
+}
|
|
|
|
|
|
- return reply->error() == QNetworkReply::NoError;
|
|
|
+void RequestClient::processRequest(QNetworkRequest& request)
|
|
|
+{
|
|
|
+ QMutexLocker locker(&m_interceptorMutex);
|
|
|
+ for (auto& interceptor : m_interceptors) {
|
|
|
+ interceptor->interceptRequest(request);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-void RequestClient::setupAsyncConnections(QNetworkReply* reply,
|
|
|
- QFutureInterface<HttpResponse>& _interface)
|
|
|
-{ // 处理网络错误信号
|
|
|
- QObject::connect(reply,
|
|
|
- &QNetworkReply::errorOccurred,
|
|
|
- [this, reply, _interface](QNetworkReply::NetworkError error) mutable {
|
|
|
- // 避免重复处理
|
|
|
- if (reply->property("handled").toBool()) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- reply->setProperty("handled", true);
|
|
|
- this->processResponse(reply);
|
|
|
-
|
|
|
- HttpResponse errorResponse;
|
|
|
- errorResponse.code = error;
|
|
|
- errorResponse.message = reply->errorString();
|
|
|
-
|
|
|
- // 特殊处理网络错误类型
|
|
|
- if (error == QNetworkReply::OperationCanceledError) {
|
|
|
- errorResponse.message = "请求被取消";
|
|
|
- } else if (error == QNetworkReply::TimeoutError) {
|
|
|
- errorResponse.message = "请求超时";
|
|
|
- } else if (error == QNetworkReply::ConnectionRefusedError) {
|
|
|
- errorResponse.message = "连接被拒绝";
|
|
|
- } else if (error == QNetworkReply::HostNotFoundError) {
|
|
|
- errorResponse.message = "找不到主机";
|
|
|
- }
|
|
|
-
|
|
|
- _interface.reportResult(errorResponse);
|
|
|
- _interface.reportFinished();
|
|
|
- });
|
|
|
-
|
|
|
- // 处理完成信号
|
|
|
- QObject::connect(reply, &QNetworkReply::finished, [this, reply, _interface]() mutable {
|
|
|
- // 避免重复处理
|
|
|
- if (reply->property("handled").toBool()) {
|
|
|
- reply->deleteLater();
|
|
|
- return;
|
|
|
- }
|
|
|
+void RequestClient::processResponse(QNetworkReply* reply)
|
|
|
+{
|
|
|
+ QMutexLocker locker(&m_interceptorMutex);
|
|
|
+ for (auto& interceptor : m_interceptors) {
|
|
|
+ interceptor->interceptResponse(reply);
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- reply->setProperty("handled", true);
|
|
|
- processResponse(reply);
|
|
|
+QByteArray RequestClient::readReplyData(QNetworkReply* reply)
|
|
|
+{
|
|
|
+ if (reply->property("cachedData").isValid()) {
|
|
|
+ return reply->property("cachedData").toByteArray();
|
|
|
+ }
|
|
|
|
|
|
- try {
|
|
|
- // 即使在 finished 信号中,也需要检查是否有错误
|
|
|
- if (reply->error() != QNetworkReply::NoError) {
|
|
|
- HttpResponse errorResponse;
|
|
|
- errorResponse.code = reply->error();
|
|
|
- errorResponse.message = reply->errorString();
|
|
|
- _interface.reportResult(errorResponse);
|
|
|
- } else {
|
|
|
- HttpResponse response = parseReplyData(reply);
|
|
|
- _interface.reportResult(response);
|
|
|
- }
|
|
|
- _interface.reportFinished();
|
|
|
- } catch (const std::exception& e) {
|
|
|
- HttpResponse errorResponse;
|
|
|
- errorResponse.code = -1;
|
|
|
- errorResponse.message = QString::fromUtf8(e.what());
|
|
|
- _interface.reportResult(errorResponse);
|
|
|
- _interface.reportFinished();
|
|
|
- }
|
|
|
+ QByteArray data = reply->readAll();
|
|
|
+ cacheReplyData(reply, data);
|
|
|
+ return data;
|
|
|
+}
|
|
|
|
|
|
- reply->deleteLater();
|
|
|
- });
|
|
|
+void RequestClient::cacheReplyData(QNetworkReply* reply, const QByteArray& data)
|
|
|
+{
|
|
|
+ reply->setProperty("cachedData", data);
|
|
|
}
|
|
|
|
|
|
// 拦截器实现
|
|
|
@@ -582,145 +455,59 @@ void AuthRequestInterceptor::interceptRequest(QNetworkRequest& request)
|
|
|
request.setRawHeader("Accept-Language", AppEvent::instance()->locale().toUtf8());
|
|
|
}
|
|
|
|
|
|
-void AuthResponseInterceptor::interceptResponse(QNetworkReply* reply)
|
|
|
+void AuthRequestInterceptor::interceptResponse(QNetworkReply* reply)
|
|
|
{
|
|
|
- // 检查是否需要刷新token
|
|
|
if (reply->error() == QNetworkReply::AuthenticationRequiredError) {
|
|
|
// 触发token刷新
|
|
|
emit AppEvent::instance()->refreshTokenNeeded();
|
|
|
|
|
|
- // 如果启用了自动刷新token,可以在这里实现
|
|
|
if (AppEvent::instance()->isEnableRefreshToken()) {
|
|
|
- doRefreshToken();
|
|
|
- } else {
|
|
|
- doReAuthenticate();
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void AuthResponseInterceptor::doRefreshToken()
|
|
|
-{
|
|
|
- // 实现刷新token的逻辑
|
|
|
- RequestClient refreshClient;
|
|
|
- QJsonObject emptyData;
|
|
|
- QJsonDocument jsonDoc(emptyData);
|
|
|
+ // 刷新token逻辑
|
|
|
+ auto client = RequestClient::baseGlobalInstance();
|
|
|
+ QJsonObject emptyData;
|
|
|
+ QJsonDocument jsonDoc(emptyData);
|
|
|
|
|
|
- QNetworkReply* reply = refreshClient.postSync("/api/auth/refresh-token", jsonDoc);
|
|
|
+ HttpResponse response = client->post("/api/auth/refresh-token", jsonDoc);
|
|
|
|
|
|
- if (reply->error() == QNetworkReply::NoError) {
|
|
|
- QByteArray responseData = reply->readAll();
|
|
|
- QJsonDocument jsonResponse = QJsonDocument::fromJson(responseData);
|
|
|
- QJsonObject jsonObject = jsonResponse.object();
|
|
|
-
|
|
|
- if (jsonObject.contains("data")) {
|
|
|
- QString newToken = jsonObject["data"].toString();
|
|
|
- AppEvent::instance()->setJwtToken(newToken);
|
|
|
+ if (response.code == 0) {
|
|
|
+ QString newToken = response.data.toString();
|
|
|
+ AppEvent::instance()->setJwtToken(newToken);
|
|
|
+ } else {
|
|
|
+ // 刷新失败,需要重新登录
|
|
|
+ AppEvent::instance()->setJwtToken("");
|
|
|
+ emit AppEvent::instance()->loginExpired(true);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 直接重新认证
|
|
|
+ AppEvent::instance()->setJwtToken("");
|
|
|
+ emit AppEvent::instance()->loginExpired(true);
|
|
|
}
|
|
|
- } else {
|
|
|
- // 刷新失败,需要重新登录
|
|
|
- doReAuthenticate();
|
|
|
}
|
|
|
-
|
|
|
- reply->deleteLater();
|
|
|
-}
|
|
|
-
|
|
|
-void AuthResponseInterceptor::doReAuthenticate()
|
|
|
-{
|
|
|
- // 实现重新认证的逻辑
|
|
|
- AppEvent::instance()->setJwtToken("");
|
|
|
- emit AppEvent::instance()->loginExpired(true);
|
|
|
}
|
|
|
|
|
|
void ErrorResponseInterceptor::interceptResponse(QNetworkReply* reply)
|
|
|
{
|
|
|
if (reply->error() != QNetworkReply::NoError) {
|
|
|
- // 解析错误信息
|
|
|
- QByteArray responseData = reply->readAll();
|
|
|
+ QByteArray responseData = reply->property("cachedData").toByteArray();
|
|
|
QString errorMessage;
|
|
|
|
|
|
- try {
|
|
|
+ if (!responseData.isEmpty()) {
|
|
|
QJsonDocument jsonResponse = QJsonDocument::fromJson(responseData);
|
|
|
- QJsonObject jsonObject = jsonResponse.object();
|
|
|
-
|
|
|
- if (jsonObject.contains("error")) {
|
|
|
- errorMessage = jsonObject["error"].toString();
|
|
|
- } else if (jsonObject.contains(messageVal)) {
|
|
|
- errorMessage = jsonObject[messageVal].toString();
|
|
|
+ if (jsonResponse.isObject()) {
|
|
|
+ QJsonObject jsonObject = jsonResponse.object();
|
|
|
+ if (jsonObject.contains("error")) {
|
|
|
+ errorMessage = jsonObject["error"].toString();
|
|
|
+ } else if (jsonObject.contains(messageVal)) {
|
|
|
+ errorMessage = jsonObject[messageVal].toString();
|
|
|
+ }
|
|
|
}
|
|
|
- } catch (...) {
|
|
|
- // 解析失败,使用默认错误信息
|
|
|
}
|
|
|
|
|
|
if (errorMessage.isEmpty()) {
|
|
|
errorMessage = reply->errorString();
|
|
|
}
|
|
|
|
|
|
- // 发送错误信息
|
|
|
emit AppEvent::instance()->errorMessage(errorMessage);
|
|
|
-
|
|
|
- // 可以根据不同的错误类型进行不同的处理
|
|
|
- switch (reply->error()) {
|
|
|
- case QNetworkReply::ConnectionRefusedError:
|
|
|
- qDebug() << "连接被拒绝" << errorMessage;
|
|
|
- break;
|
|
|
- case QNetworkReply::RemoteHostClosedError:
|
|
|
- qDebug() << "远程主机关闭连接" << errorMessage;
|
|
|
- break;
|
|
|
- case QNetworkReply::HostNotFoundError:
|
|
|
- qDebug() << "主机未找到" << errorMessage;
|
|
|
- break;
|
|
|
- case QNetworkReply::TimeoutError:
|
|
|
- qDebug() << "连接超时" << errorMessage;
|
|
|
- break;
|
|
|
- case QNetworkReply::OperationCanceledError:
|
|
|
- qDebug() << "操作被取消" << errorMessage;
|
|
|
- break;
|
|
|
- case QNetworkReply::SslHandshakeFailedError:
|
|
|
- qDebug() << "SSL握手失败" << errorMessage;
|
|
|
- break;
|
|
|
- case QNetworkReply::TemporaryNetworkFailureError:
|
|
|
- qDebug() << "临时网络故障" << errorMessage;
|
|
|
- break;
|
|
|
- case QNetworkReply::NetworkSessionFailedError:
|
|
|
- qDebug() << "网络会话失败" << errorMessage;
|
|
|
- break;
|
|
|
- case QNetworkReply::BackgroundRequestNotAllowedError:
|
|
|
- qDebug() << "不允许后台请求" << errorMessage;
|
|
|
- break;
|
|
|
- case QNetworkReply::ContentReSendError:
|
|
|
- qDebug() << "内容重发错误" << errorMessage;
|
|
|
- break;
|
|
|
- default:
|
|
|
- qDebug() << "其他网络错误" << errorMessage;
|
|
|
- break;
|
|
|
- }
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
-// 创建全局客户端实例
|
|
|
-static RequestClient* requestClientInstance = nullptr;
|
|
|
-static RequestClient* baseRequestClientInstance = nullptr;
|
|
|
-
|
|
|
-RequestClient* RequestClient::requestClient(const RequestClientOptions& defaultOptions)
|
|
|
-{
|
|
|
- if (!requestClientInstance) {
|
|
|
- RequestClientOptions options = defaultOptions;
|
|
|
- options.enableDefaultInterceptors = true;
|
|
|
- options.responseReturn = "data";
|
|
|
- requestClientInstance = createClient(options.baseURL, options);
|
|
|
- }
|
|
|
- return requestClientInstance;
|
|
|
-}
|
|
|
-
|
|
|
-RequestClient* RequestClient::baseRequestClient(const RequestClientOptions& defaultOptions)
|
|
|
-{
|
|
|
- if (!baseRequestClientInstance) {
|
|
|
- RequestClientOptions options = defaultOptions;
|
|
|
- options.enableDefaultInterceptors = false;
|
|
|
- options.responseReturn = "data";
|
|
|
- baseRequestClientInstance = createClient(options.baseURL, options);
|
|
|
- }
|
|
|
- return baseRequestClientInstance;
|
|
|
-}
|
|
|
-
|
|
|
} // namespace TC
|