借助Qt的NetWork模块,可以轻松的实现HTTP的Get/Post请求,而不需要再次引用像libcurl这样的第三方库。
当然,Qt的NetWork模块提供的功能远远不只是HTTP方面的。
头文件
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QNetworkAccessManager>
另外,使用Qt网络模块还需要引用Qt5Network.lib库。
Get
先构造一个QNetworkAccessManager对象,QNetworkAccessManager对象提供了发送QNetworkRequest网络请求和接收QNetworkReply网络回复的功能。
QNetworkAccessManager还提供了缓存和Cookie管理、代理设置等功能。详见:https://doc.qt.io/qt-5/qnetworkaccessmanager.html
QNetworkRequest提供了对本次网络请求的封装,在本示例中只是构造了一个最简单的requset,没有进行任何参数设置。
QNetworkRequest提供了很多方法来对请求进行配置,比如我们可以使用QNetworkRequest::setHeader设置请求头等。
void QtGuiApplication::onBtnGetClicked() {
QNetworkRequest request;
QNetworkAccessManager* naManager = new QNetworkAccessManager(this);
QMetaObject::Connection connRet = QObject::connect(naManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
Q_ASSERT(connRet);
request.setUrl(QUrl("https://www.baidu.com"));
QNetworkReply* reply = naManager->get(request);
}
请求是异步的,当请求完成之后,会调用void requestFinished(QNetworkReply* reply);
槽函数:
void QtGuiApplication::requestFinished(QNetworkReply* reply) {
// 获取http状态码
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if(statusCode.isValid())
qDebug() << "status code=" << statusCode.toInt();
QVariant reason = reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
if(reason.isValid())
qDebug() << "reason=" << reason.toString();
QNetworkReply::NetworkError err = reply->error();
if(err != QNetworkReply::NoError) {
qDebug() << "Failed: " << reply->errorString();
}
else {
// 获取返回内容
qDebug() << reply->readAll();
}
}
Post
void QtGuiApplication::onBtnPushClicked() {
QNetworkRequest request;
QNetworkAccessManager* naManager = new QNetworkAccessManager(this);
QMetaObject::Connection connRet = QObject::connect(naManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
Q_ASSERT(connRet);
request.setUrl(QUrl("https://www.baidu.com"));
QString testData = "test";
QNetworkReply* reply = naManager->post(request, testData.toUtf8());
}
同样,请求也是异步的,当请求完成之后,会调用void requestFinished(QNetworkReply* reply);
槽函数(和Get一样):
void QtGuiApplication::requestFinished(QNetworkReply* reply) {
// 获取http状态码
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if(statusCode.isValid())
qDebug() << "status code=" << statusCode.toInt();
QVariant reason = reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
if(reason.isValid())
qDebug() << "reason=" << reason.toString();
QNetworkReply::NetworkError err = reply->error();
if(err != QNetworkReply::NoError) {
qDebug() << "Failed: " << reply->errorString();
}
else {
// 获取返回内容
qDebug() << reply->readAll();
}
}
具体实例:
异步通信实例:
当涉及到Qt与HTTP通信时,可以使用Qt的QNetworkAccessManager类进行POST和GET请求的发送。下面是一个封装了POST和GET请求的示例,同时支持传入JSON格式参数:
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QJsonObject>
#include <QJsonDocument>
#include <QVariantMap>
class HttpHelper : public QObject
{
Q_OBJECT
public:
HttpHelper(QObject* parent = nullptr)
: QObject(parent)
{
networkManager = new QNetworkAccessManager(this);
connect(networkManager, &QNetworkAccessManager::finished, this, &HttpHelper::onReplyReceived);
}
void sendPostRequest(const QString& url, const QVariantMap& parameters)
{
QJsonDocument jsonDoc = QJsonDocument::fromVariant(QVariant(parameters));
QByteArray postData = jsonDoc.toJson();
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
networkManager->post(request, postData);
}
void sendGetRequest(const QString& url, const QVariantMap& parameters)
{
QUrl requestUrl(url);
QUrlQuery urlQuery;
for (const QString& key : parameters.keys()) {
urlQuery.addQueryItem(key, parameters.value(key).toString());
}
requestUrl.setQuery(urlQuery);
QNetworkRequest request(requestUrl);
networkManager->get(request);
}
signals:
void replyReceived(const QByteArray& responseData);
private slots:
void onReplyReceived(QNetworkReply* reply)
{
if (reply->error() == QNetworkReply::NoError) {
QByteArray responseData = reply->readAll();
emit replyReceived(responseData);
} else {
// Handle error case
}
reply->deleteLater();
}
private:
QNetworkAccessManager* networkManager;
};
在上述示例中,HttpHelper类封装了QNetworkAccessManager来发送POST和GET请求。sendPostRequest和sendGetRequest方法分别用于发送POST和GET请求,并接受一个QVariantMap类型的参数,该参数将作为JSON格式的数据发送到服务器。
通过QJsonDocument,将QVariantMap转换为JSON格式的QByteArray,并将其作为POST请求的数据发送。
对于GET请求,使用QUrlQuery将参数添加到URL中。
在收到HTTP响应后,通过QNetworkAccessManager的finished信号和onReplyReceived槽函数进行处理。如果没有错误发生,则读取响应数据并通过replyReceived信号进行传递。
使用示例:
HttpHelper httpHelper;
// 发送POST请求
QVariantMap postData;
postData["name"] = "John Doe";
postData["age"] = 30;
httpHelper.sendPostRequest("https://example.com/api", postData);
// 发送GET请求
QVariantMap getParams;
getParams["param1"] = "value1";
getParams["param2"] = "value2";
httpHelper.sendGetRequest("https://example.com/api", getParams);
可以连接HttpHelper的replyReceived信号,以接收HTTP响应数据。
connect(&httpHelper, &HttpHelper::replyReceived, this, &MyClass::handleResponse);
void MyClass::handleResponse(const QByteArray& responseData)
{
// 处理响应数据
}
在上述示例中,封装的HTTP请求方法是异步的。
QNetworkAccessManager使用异步方式发送请求,并通过信号和槽机制来处理响应。
当请求完成时,会发出finished信号,然后调用onReplyReceived槽函数来处理响应数据。
这种异步方式允许应用程序在等待响应时继续执行其他任务,而不会被阻塞。一旦响应可用,会触发相应的信号,以便应用程序能够及时处理响应数据。
在使用封装的HttpHelper类时,你可以连接其replyReceived信号,并在槽函数中处理响应数据。这样可以确保在收到响应后及时进行处理。
如果你需要实现同步的消息传递,可以使用Qt的事件循环机制来等待并处理HTTP请求的响应。下面是一个示例:
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QJsonObject>
#include <QJsonDocument>
#include <QVariantMap>
#include <QEventLoop>
class HttpHelper : public QObject
{
Q_OBJECT
public:
HttpHelper(QObject* parent = nullptr)
: QObject(parent)
{
networkManager = new QNetworkAccessManager(this);
}
QByteArray sendPostRequest(const QString& url, const QVariantMap& parameters)
{
QJsonDocument jsonDoc = QJsonDocument::fromVariant(QVariant(parameters));
QByteArray postData = jsonDoc.toJson();
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QNetworkReply* reply = networkManager->post(request, postData);
QEventLoop eventLoop;
connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
eventLoop.exec();
QByteArray responseData;
if (reply->error() == QNetworkReply::NoError) {
responseData = reply->readAll();
}
reply->deleteLater();
return responseData;
}
QByteArray sendGetRequest(const QString& url, const QVariantMap& parameters)
{
QUrl requestUrl(url);
QUrlQuery urlQuery;
for (const QString& key : parameters.keys()) {
urlQuery.addQueryItem(key, parameters.value(key).toString());
}
requestUrl.setQuery(urlQuery);
QNetworkRequest request(requestUrl);
QNetworkReply* reply = networkManager->get(request);
QEventLoop eventLoop;
connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
eventLoop.exec();
QByteArray responseData;
if (reply->error() == QNetworkReply::NoError) {
responseData = reply->readAll();
}
reply->deleteLater();
return responseData;
}
private:
QNetworkAccessManager* networkManager;
};
在这个示例中,HttpHelper类中的sendPostRequest和sendGetRequest方法是同步的,它们会在等待响应期间阻塞事件循环,直到收到响应为止。
通过创建QEventLoop对象并连接QNetworkReply的finished信号,我们可以在调用exec()方法后等待响应。
一旦收到响应,事件循环退出,继续执行后续代码。然后我们读取响应数据并返回。
使用示例:
HttpHelper httpHelper;
// 发送同步POST请求
QVariantMap postData;
postData["name"] = "John Doe";
postData["age"] = 30;
QByteArray postResponse = httpHelper.sendPostRequest("https://example.com/api", postData);
// 处理postResponse
// 发送同步GET请求
QVariantMap getParams;
getParams["param1"] = "value1";
getParams["param2"] = "value2";
QByteArray getResponse = httpHelper.sendGetRequest("https://example.com/api", getParams);
// 处理getResponse
需要注意的是,使用同步方式发送HTTP请求会导致阻塞事件循环,这可能会对应用程序的响应性产生负面影响。因此,在考虑使用同步方式时,请仔细评估你的应用程序需求和性能要求。