PowerMaster/source/httpRequestManager.cpp

319 lines
8.5 KiB
C++
Raw Normal View History

#include "httpRequestManager.h"
#include <QJsonObject>
#include <QJsonArray>
#include <QDebug>
HttpRequestManager::HttpRequestManager(QObject* parent)
: QObject(parent)
{
}
HttpRequestManager::~HttpRequestManager()
{
for(auto& config : m_endpoints)
{
if(config.activeReply)
{
config.activeReply->abort();
config.activeReply->deleteLater();
config.activeReply = nullptr;
}
if(config.timeoutTimer)
{
config.timeoutTimer->stop();
config.timeoutTimer->deleteLater();
config.timeoutTimer = nullptr;
}
}
}
void HttpRequestManager::sendRequest(EndpointConfig& config)
{
QNetworkRequest request(config.url);
for(auto it = config.headers.constBegin(); it != config.headers.constEnd(); ++it)
request.setRawHeader(it.key(), it.value());
QNetworkReply* reply = nullptr;
if(config.method == "GET")
reply = m_networkManager.get(request);
else if(config.method == "POST")
reply = m_networkManager.post(request, config.body);
else if(config.method == "PUT")
reply = m_networkManager.put(request, config.body);
else if(config.method == "DELETE")
reply = m_networkManager.deleteResource(request);
else
{
qWarning() << "Unsupported HTTP method:" << config.method;
emit requestFailed(config.dataKey, "Unsupported HTTP method");
return;
}
connect(reply, &QNetworkReply::finished, this, &HttpRequestManager::onReplyFinished);
connect(reply, &QNetworkReply::errorOccurred, this, &HttpRequestManager::onReplyError);
config.timeoutTimer = new QTimer(this);
config.timeoutTimer->setSingleShot(true);
config.timeoutTimer->setInterval(m_defaultTimeout);
connect(config.timeoutTimer, &QTimer::timeout, this, [this, &config](){
handleRequestTimeout(config.dataKey);
});
}
void HttpRequestManager::handleResponse(const QString& dataKey, QNetworkReply* reply)
{
if(!m_endpoints.contains(dataKey))
{
qWarning() << "Recived response for unregistered dataKey:" << dataKey;
reply->deleteLater();
return;
}
EndpointConfig& config = m_endpoints[dataKey];
//关闭超时重连定时器
if(config.timeoutTimer)
{
config.timeoutTimer->stop();
config.timeoutTimer->deleteLater();
config.timeoutTimer = nullptr;
}
if(reply->error() != QNetworkReply::NoError)
return; //具体错误信息在onReplyError中进行处理
QByteArray responseData = reply->readAll();
QString contentType = reply->header(QNetworkRequest::ContentTypeHeader).toString();
if(contentType.contains("application/json"))
parseJsonResponse(dataKey, responseData);
else if(contentType.contains("text/"))
parseTextResponse(dataKey, responseData);
else
parseBinaryResponse(dataKey, responseData);
//数据重置
reply->deleteLater();
config.retryCount = 0;
config.activeReply = nullptr;
}
void HttpRequestManager::handleRequestTimeout(const QString& dataKey)
{
if(!m_endpoints.contains(dataKey))
return;
EndpointConfig& config = m_endpoints[dataKey];
qWarning() << "Request timeout for dataKey: " << dataKey;
if(config.activeReply)
config.activeReply->abort();
//重试
if(config.retryCount < config.maxRetries)
scheduleRetry(config.dataKey);
else
{
emit requestFailed(config.dataKey, "Request timed out");
config.retryCount = 0;
}
}
void HttpRequestManager::scheduleRetry(const QString& dataKey)
{
if(!m_endpoints.contains(dataKey))
return;
EndpointConfig& config = m_endpoints[dataKey];
config.retryCount++;
QTimer::singleShot(config.retryInterval, this, [this, dataKey](){
requestData(dataKey);
});
}
void HttpRequestManager::parseJsonResponse(const QString& dataKey, const QByteArray& data)
{
QJsonParseError parseError;
QJsonDocument document = QJsonDocument::fromJson(data, &parseError);
if(document.isNull())
{
emit requestFailed(dataKey, "get JSonDocument failed");
return;
}
if(parseError.error != QJsonParseError::NoError)
{
emit requestFailed(dataKey, "JSON parse error: " + parseError.errorString());
return;
}
if(document.isObject())
emit dataReceived(dataKey, document.object().toVariantMap());
else if(document.isArray())
emit dataReceived(dataKey, document.array().toVariantList());
else
emit dataReceived(dataKey, QVariant());
}
void HttpRequestManager::parseTextResponse(const QString& dataKey, const QByteArray& data)
{
emit dataReceived(dataKey, QString::fromUtf8(data));
}
void HttpRequestManager::parseBinaryResponse(const QString& dataKey, const QByteArray& data)
{
emit dataReceived(dataKey, data);
}
void HttpRequestManager::registerEndpoint(const QString& dataKey, const QUrl& url, const QByteArray& method,
const QByteArray& body, const QMap<QByteArray, QByteArray>& headers)
{
EndpointConfig config;
config.dataKey = dataKey;
config.url = url;
config.method = method.toUpper();
config.body = body;
config.headers = headers;
config.maxRetries = m_maxRetries;
config.retryInterval = m_retryIntrval;
m_endpoints[dataKey] = config;
}
void HttpRequestManager::requestData(const QString& dataKey)
{
if(!m_endpoints.contains(dataKey))
{
qWarning() << "This dataKey is not present in endpoints: " << dataKey;
emit requestFailed(dataKey, "dataKey is not present in endpoints");
return;
}
EndpointConfig& config = m_endpoints[dataKey];
if(config.activeReply)
{
config.activeReply->abort();
config.activeReply->deleteLater();
config.activeReply = nullptr;
}
if(config.timeoutTimer)
{
config.timeoutTimer->stop();
config.timeoutTimer->deleteLater();
config.timeoutTimer = nullptr;
}
sendRequest(config);
}
void HttpRequestManager::cancleRequest(const QString& dataKey)
{
if(!m_endpoints.contains(dataKey))
return;
EndpointConfig& config = m_endpoints[dataKey];
if(config.activeReply)
{
config.activeReply->abort();
config.activeReply->deleteLater();
config.activeReply = nullptr;
}
if(config.timeoutTimer)
{
config.timeoutTimer->stop();
config.timeoutTimer->deleteLater();
config.timeoutTimer = nullptr;
}
config.retryCount = 0;
}
void HttpRequestManager::setDefaultTimeout(int ms)
{
m_defaultTimeout = qMax(1000, ms);
}
void HttpRequestManager::setRetryPolicy(int maxRetries, int retryInterval)
{
m_maxRetries = qMax(0, maxRetries);
m_retryIntrval = qMax(500, retryInterval);
//更新所以已注册端点的充实策略
for(auto& config : m_endpoints)
{
config.maxRetries = m_maxRetries;
config.retryInterval = m_retryIntrval;
}
}
bool HttpRequestManager::hasVaildEndpoint(const QString& dataKey)
{
return m_endpoints.contains(dataKey) && m_endpoints[dataKey].url.isEmpty();
}
void HttpRequestManager::onReplyFinished()
{
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
if(!reply)
return;
QString dataKey;
for(auto& config : m_endpoints)
{
if(config.activeReply == reply)
{
dataKey = config.dataKey;
break;
}
}
if(dataKey.isEmpty())
{
reply->deleteLater();
return;
}
handleResponse(dataKey, reply);
}
void HttpRequestManager::onReplyError(QNetworkReply::NetworkError code)
{
Q_UNUSED(code);
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
if(!reply)
return;
QString dataKey;
for(auto& config : m_endpoints)
{
if(config.activeReply == reply)
{
dataKey = config.dataKey;
break;
}
}
if(dataKey.isEmpty())
return;
EndpointConfig& config = m_endpoints[dataKey];
//关闭超时重连定时器
if(config.timeoutTimer)
{
config.timeoutTimer->stop();
config.timeoutTimer->deleteLater();
config.timeoutTimer = nullptr;
}
//打印错误
QString error = reply->errorString();
qWarning() << "HTTP request failed for " << dataKey << ":" << error;
//重试
if(config.retryCount < config.maxRetries)
scheduleRetry(dataKey);
else
{
emit requestFailed(dataKey, error);
config.retryCount = 0;
}
reply->deleteLater();
config.activeReply = nullptr;
}