QNetworkAccessManager实现的HTTP异步接口调用问题解决

本文介绍了在C++中使用QNetworkAccessManager进行网络请求时遇到的问题,即主线程中析构可能导致的异常。文章提供了使用QPointer、信号与槽以及记录网络请求量等三种解决办法,并指出静态变量不推荐使用。
摘要由CSDN通过智能技术生成


一、问题描述

QNetworkAccessManager无疑是C++中比较强大的网络库,其中就能够利用它实现http网络请求的功能,但是在我的某个应用场景中可能会有以下问题:

//封装好的网络接口
void HttpRequest::postDataToServerAsync(const QString &httpPath, const QByteArray &postBody,std::function<void (const HttpResultPackge &)> &callBack)
{
//...
QNetworkAccessManager *netAm = new QNetworkAccessManager();
connect(netAm, &QNetworkAccessManager::finished, this, [callBack](QNetworkReply *amReply){
		HttpResultPackge result;
		//...
		callBack(result);
});
auto reply = netAm->post(request, postBody);
//...
}

上述代码为一种常见的异步网络接口实现方法,在http数据返回后通过callBack返回到调用者去执行后续代码

void MainWindow::httpPost()
{
	HttpRequest::getInstance().postDataToServerAsync(httpPath, postBody, [this](const HttpResultPackge &data){
	//...
	});
}

但是这种方法有一种情况会使程序出现异常:当MainWindow调用请求后又进行析构,之后网络请求数据到达后通过callBack进入lambda函数中,假如该函数有使用MainWindow中的成员变量就会发送异常,这种情况在网络状态不好的时候经常发生


提示:以下是本篇文章正文内容,下面案例可供参考

二、解决办法

1.使用QPointer

利用QT中的QPointer特性,构造一个指向MainWindow的QPointer,将QPointer捕捉到lambda函数中,之后判断一下MainWindow是否为空

void MainWindow::httpPost()
{
	QPointer<MainWindow> p(this);
	HttpRequest::getInstance().postDataToServerAsync(httpPath, postBody, [this, p](const HttpResultPackge &data){
	if(p.isNull())
		return;
	//...使用了this中的变量
	});
}

注意:此方法仅限于继承QObject的对象

2.利用信号与槽

参考qobject.cpp中的QObject::~QObject()函数,当对象析构后,会将所有相关的信号和槽断开连接
在这里插入图片描述
因此只需要编写一个信号转发类,然后用MainWindow去接受信号,当MainWindow被析构时,连接自动断开,也就不会处理槽函数的内容了

class HttpFinishedSender : public QObject
{
	Q_OBJECT
signals:
	void httpFinished(const HttpResultPackge &data);	
}
//......
void MainWindow::httpPost()
{
	auto httpSender = new HttpFinishedSender(this);
	connect(httpSender, &HttpFinishedSender::httpFinished, this, [this](const HttpResultPackge &data){
		//...使用了this中的变量
	});
	HttpRequest::getInstance().postDataToServerAsync(httpPath, postBody, [httpSender](const HttpResultPackge &data){
		emit httpSender->httpFinished(data);
		delete httpSender;
	});
}

注意:此方法仅限于继承QObject的对象

4.记录网络请求量

在成员变量中使用一个变量专门管理当前对象正在进行的网络请求数量,之后在析构中阻塞判断,直到所有请求完毕

MainWindow::~MainWindow()
{
	//TODO 中断网络请求
	
	while(m_httpNum > 0){

		//主线程可添加事件循环避免卡界面
		QEventLoop loop;
		loop.processEvents(QEventLoop::AllEvents, 200);
	}
}

此方法需要Http请求类去手动实现中断机制,不然在弱网环境下会循环很久,对于前端来说还好用户感知不到,但是对后端来说会消耗很高的性能不推荐使用

3.静态变量(不推荐)

此方法只适用于同时存在一个对象,繁杂还不标准,并且可能有未知的不确定性,如果调用者确实不能继承QObject可考虑使用

static bool isDelete = false;
//在构造和析构时都需要处理静态变量
MainWindow::MainWindow()
{
	isDelete = false;
}
MainWindow::~MainWindow()
{
	isDelete = true;
}
void MainWindow::httpPost()
{
	HttpRequest::getInstance().postDataToServerAsync(httpPath, postBody, [this, p](const HttpResultPackge &data){
		if(isDelete)
			return;
		//...使用了this中的变量
	});
}
  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QT提供了QNetworkAccessManager类来实现HTTP请求的异步处理,可以使用post和get方法发送异步请求。 对于POST请求,可以使用QNetworkRequest和QByteArray来设置请求的URL和payload数据,然后调用QNetworkAccessManager的post方法发送请求。示例代码如下: ```cpp QNetworkRequest request; request.setUrl(QUrl("http://example.com")); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); QByteArray postData; // 设置payload数据 postData.append("key1=value1"); postData.append("&key2=value2"); QNetworkReply* reply = manager->post(request, postData); // 处理reply的异步响应 ``` 对于GET请求,可以使用QNetworkRequest来设置请求的URL,然后调用QNetworkAccessManager的get方法发送请求。示例代码如下: ```cpp QNetworkRequest request; request.setUrl(QUrl("http://example.com")); QNetworkReply* reply = manager->get(request); // 处理reply的异步响应 ``` 发送请求后,QNetworkAccessManager将返回一个QNetworkReply对象,它用于处理异步响应。可以通过连接reply的信号与槽来处理响应数据,例如readyRead信号表示有可读取的数据,可以调用reply的readAll方法来读取数据。 需要注意的是,由于请求是异步的,因此可以通过QEventLoop等待请求完成后再继续执行后续代码,或者使用信号与槽连接reply的finished信号来处理请求完成后的操作。 以上就是使用QT实现POST和GET异步请求的简单示例,通过QNetworkAccessManager的post和get方法可以轻松地实现异步HTTP请求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值