#include "networkaccessmanager.h" #include "appevent.h" #include #include #include #include #include #include #include // 基础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; void cleanupNetworkAccessManager() { delete namInstance; namInstance = nullptr; } NetworkAccessManager* NetworkAccessManager::instance() { if (!namInstance) { namInstance = new NetworkAccessManager; qAddPostRoutine(cleanupNetworkAccessManager); } return namInstance; } NetworkAccessManager::NetworkAccessManager(QObject* parent) : QNetworkAccessManager(parent) { // #ifdef QT_DEBUG // connect(this, &QNetworkAccessManager::finished, this, [](QNetworkReply* reply) { // const auto data = reply->readAll(); // reply->seek(0); // const auto startTimeValue = reply->property("startTime"); // const QDateTime startTime = startTimeValue.value(); // const QDateTime endTime = QDateTime::currentDateTime(); // qDebug() << QString("[%1] time:[%2]ms --> %3") // .arg(endTime.toString("yyyy-MM-dd hh:mm:ss.zzz")) // .arg((endTime.msecsTo(startTime))) // .arg(QString::fromUtf8(data)); // }); // #endif } QNetworkReply* NetworkAccessManager::createRequest(Operation op, const QNetworkRequest& request, QIODevice* outgoingData) { QNetworkRequest req(request); // 记录请求开始时间 QDateTime startTime = QDateTime::currentDateTime(); // 获取操作类型字符串 QString opStr; switch (op) { case QNetworkAccessManager::GetOperation: opStr = "GET"; break; case QNetworkAccessManager::PostOperation: opStr = "POST"; break; case QNetworkAccessManager::PutOperation: opStr = "PUT"; break; case QNetworkAccessManager::DeleteOperation: opStr = "DELETE"; break; case QNetworkAccessManager::HeadOperation: opStr = "HEAD"; break; default: opStr = "UNKNOWN"; break; } qDebug() << QString("[%1] --> %2 %3") .arg(startTime.toString("yyyy-MM-dd hh:mm:ss.zzz")) .arg(opStr) .arg(request.url().toString()); // 默认的请求处理 QString agentStr = QString::fromLatin1("%1/%2 (QNetworkAccessManager %3; %4; %5; %6 bit)") .arg(QCoreApplication::applicationName(), QCoreApplication::applicationVersion(), QLatin1String(qVersion()), QSysInfo::prettyProductName(), QLocale::system().name()) .arg(QSysInfo::WordSize); req.setRawHeader("User-Agent", agentStr.toLatin1()); const QString token = AppEvent::instance()->jwtToken(); if (!token.isEmpty()) { req.setRawHeader("Authorization", "Bearer " + token.toUtf8()); } req.setRawHeader("Machine-Code", AppEvent::instance()->machineCode().toUtf8()); req.setRawHeader("Accept-Language", AppEvent::instance()->locale().toUtf8()); const QUrl& url = request.url(); const QString urlPath = url.path(); if (!urlPath.contains("/api/auth/refresh-token") && !urlPath.contains("/api/auth/login")) { if (AppEvent::instance()->isRefreshToken()) { emit AppEvent::instance()->refreshTokenNeeded(); } } QNetworkReply* reply = QNetworkAccessManager::createRequest(op, req, outgoingData); // 存储开始时间,用于计算请求耗时 reply->setProperty("startTime", startTime); return reply; } 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) { // 初始化默认拦截器 if (options.enableDefaultInterceptors) { setupDefaultInterceptors(); } } RequestClient* RequestClient::createClient(const QString& baseURL, const RequestClientOptions& options) { RequestClientOptions opts = options; opts.baseURL = baseURL; return new RequestClient(opts); } void RequestClient::setupDefaultInterceptors() { // 添加认证拦截器 auto authRequestInterceptor = new AuthRequestInterceptor(); addInterceptor(authRequestInterceptor); // 添加响应拦截器 auto authResponseInterceptor = new AuthResponseInterceptor(); addInterceptor(authResponseInterceptor); // 添加错误处理拦截器 auto errorInterceptor = new ErrorResponseInterceptor(); addInterceptor(errorInterceptor); } void RequestClient::addInterceptor(Interceptor* interceptor) { if (!interceptors.contains(interceptor)) { interceptors.append(interceptor); } } void RequestClient::removeInterceptor(Interceptor* interceptor) { interceptors.removeOne(interceptor); } void RequestClient::setBaseUrl(const QString& url) { m_baseUrl = url; } QString RequestClient::baseUrl() const { if (m_baseUrl.isEmpty()) { return base_url; } return m_baseUrl; } void RequestClient::setTimeout(int timeout) { m_timeout = timeout; } int RequestClient::timeout() const { return m_timeout; } QNetworkReply* RequestClient::getSync(const QString& url, const QVariantMap& params) { QNetworkReply* reply = get(url, params); // 同步等待 QEventLoop loop; QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); // 处理响应拦截器 processResponse(reply); return reply; } QNetworkReply* RequestClient::postSync(const QString& url, const QJsonDocument& data) { QNetworkReply* reply = post(url, data); // 同步等待 QEventLoop loop; QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); // 处理响应拦截器 processResponse(reply); return reply; } QNetworkReply* RequestClient::putSync(const QString& url, const QJsonDocument& data) { QNetworkReply* reply = put(url, data); // 同步等待 QEventLoop loop; QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); // 处理响应拦截器 processResponse(reply); return reply; } QNetworkReply* RequestClient::deleteSync(const QString& url) { QNetworkReply* reply = deleteResource(url); // 同步等待 QEventLoop loop; QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); // 处理响应拦截器 processResponse(reply); return reply; } QNetworkReply* RequestClient::uploadSync(const QString& url, QHttpMultiPart* multiPart) { QNetworkReply* reply = upload(url, multiPart); // 同步等待 QEventLoop loop; QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); // 处理响应拦截器 processResponse(reply); return reply; } QFuture RequestClient::getAsync(const QString& url, const QVariantMap& params) { QFutureInterface interface; interface.reportStarted(); QNetworkReply* reply = get(url, params); setupAsyncConnections(reply, interface); return interface.future(); } QFuture RequestClient::postAsync(const QString& url, const QJsonDocument& data) { QFutureInterface interface; interface.reportStarted(); QNetworkReply* reply = post(url, data); setupAsyncConnections(reply, interface); return interface.future(); } QFuture RequestClient::putAsync(const QString& url, const QJsonDocument& data) { QFutureInterface interface; interface.reportStarted(); QNetworkReply* reply = put(url, data); setupAsyncConnections(reply, interface); return interface.future(); } QFuture RequestClient::deleteAsync(const QString& url) { QFutureInterface interface; interface.reportStarted(); QNetworkReply* reply = deleteResource(url); setupAsyncConnections(reply, interface); return interface.future(); } QFuture RequestClient::uploadAsync(const QString& url, QHttpMultiPart* multiPart) { QFutureInterface interface; interface.reportStarted(); QNetworkReply* reply = upload(url, multiPart); setupAsyncConnections(reply, interface); return interface.future(); } HttpResponse RequestClient::parseReplyData(QNetworkReply* reply) { HttpResponse response; if (reply->error() != QNetworkReply::NoError) { response.code = reply->error(); response.message = reply->errorString(); return response; } 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; } } return response; } void RequestClient::processRequest(QNetworkRequest& request) { for (auto interceptor : interceptors) { interceptor->interceptRequest(request); } } void RequestClient::processResponse(QNetworkReply* reply) { for (auto interceptor : interceptors) { interceptor->interceptResponse(reply); } } QNetworkReply* RequestClient::get(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)); QUrlQuery query; for (auto it = params.constBegin(); it != params.constEnd(); ++it) { query.addQueryItem(it.key(), it.value().toString()); } if (!params.isEmpty()) { fullUrl.setQuery(query); } QNetworkRequest modifiedRequest(fullUrl); modifiedRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); processRequest(modifiedRequest); QNetworkReply* reply = manager->get(modifiedRequest); return reply; } QNetworkReply* RequestClient::post(const QString& url, const QJsonDocument& data) { QNetworkAccessManager* manager = NetworkAccessManager::instance(); manager->setTransferTimeout(m_timeout); QUrl fullUrl(m_baseUrl.isEmpty() ? QString(base_url).append(url) : m_baseUrl.append(url)); QBuffer* buffer = new QBuffer; buffer->setData(data.toJson()); buffer->open(QIODevice::ReadOnly); QNetworkRequest modifiedRequest(fullUrl); modifiedRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); processRequest(modifiedRequest); QNetworkReply* reply = manager->post(modifiedRequest, buffer); buffer->setParent(reply); return reply; } QNetworkReply* RequestClient::put(const QString& url, const QJsonDocument& data) { QNetworkAccessManager* manager = NetworkAccessManager::instance(); manager->setTransferTimeout(m_timeout); QUrl fullUrl(m_baseUrl.isEmpty() ? QString(base_url).append(url) : m_baseUrl.append(url)); QBuffer* buffer = new QBuffer; buffer->setData(data.toJson()); buffer->open(QIODevice::ReadOnly); QNetworkRequest modifiedRequest(fullUrl); processRequest(modifiedRequest); QNetworkReply* reply = manager->put(modifiedRequest, buffer); buffer->setParent(reply); return reply; } QNetworkReply* RequestClient::deleteResource(const QString& url) { QNetworkAccessManager* manager = NetworkAccessManager::instance(); manager->setTransferTimeout(m_timeout); QUrl fullUrl(m_baseUrl.isEmpty() ? QString(base_url).append(url) : m_baseUrl.append(url)); QNetworkRequest modifiedRequest(fullUrl); processRequest(modifiedRequest); QNetworkReply* reply = manager->deleteResource(modifiedRequest); return reply; } QNetworkReply* RequestClient::upload(const QString& url, QHttpMultiPart* multiPart) { QNetworkAccessManager* manager = NetworkAccessManager::instance(); manager->setTransferTimeout(m_timeout); QUrl fullUrl(m_baseUrl.isEmpty() ? QString(base_url).append(url) : m_baseUrl.append(url)); QNetworkRequest modifiedRequest(fullUrl); QNetworkReply* reply = manager->post(modifiedRequest, multiPart); return reply; } bool RequestClient::download(const QString& url, const QString& saveFilePath) { QNetworkReply* reply = get(url); QEventLoop loop; QFile file(saveFilePath); if (!file.open(QIODevice::WriteOnly)) { return false; } QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); QObject::connect(reply, &QNetworkReply::readyRead, [&]() { file.write(reply->readAll()); }); loop.exec(); file.close(); return reply->error() == QNetworkReply::NoError; } void RequestClient::setupAsyncConnections(QNetworkReply* reply, QFutureInterface& _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; } reply->setProperty("handled", true); processResponse(reply); 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(); } reply->deleteLater(); }); } // 拦截器实现 void AuthRequestInterceptor::interceptRequest(QNetworkRequest& request) { const QString token = AppEvent::instance()->jwtToken(); if (!token.isEmpty()) { request.setRawHeader("Authorization", "Bearer " + token.toUtf8()); } request.setRawHeader("Machine-Code", AppEvent::instance()->machineCode().toUtf8()); request.setRawHeader("Accept-Language", AppEvent::instance()->locale().toUtf8()); } void AuthResponseInterceptor::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); QNetworkReply* reply = refreshClient.postSync("/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); } } 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(); QString errorMessage; try { 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(); } } 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