一、概述
QNetworkAccessManager 其实就是一个访问网络接口的管理工具类,该对象保存了它发送的请求的公共配置和设置(其实就是 QNetworkRequest 里的配置数据)。它包含代理和缓存配置,以及与此类问题相关的信号,以及可用于监视网络操作进展的应答信号,也就是下载进度、上传进度等信号。
一个QNetworkAccessManager实例对整个Qt应用程序来说就足够了。由于QNetworkAccessManager是基于QObject的,它只能从它所属的线程使用。
一旦创建了QNetworkAccessManager对象,应用程序就可以使用它通过网络发送请求。它提供了一组标准函数,接收一个请求和可选的数据,每个函数返回一个QNetworkReply对象。返回对象用于获取响应相应请求而返回的任何数据。
二、基础用法
1. 下载数据
通过以下的基本方式可以完成一个简单的网络下载:
使用的即是 get() 方法,这个就是只下载而不会回上传数据到服务器之类的,上传服务器即是要用 post() 方法
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
//因为是发送请求到接收到数据是异步的,replyFinished 就是处理请求完成后的槽函数
connect(manager, &QNetworkAccessManager::finished,
this, &MyClass::replyFinished);
//通过请求获取到数据
manager->get(QNetworkRequest(QUrl("http://qt-project.org")));
QNetworkAccessManager有一个异步API。当上面的replyFinished槽函数被调用时,它接受的参数是QNetworkReply对象,其中包含下载的数据以及元数据(首部等)。 这个get 方法只是下载
- 注意:请求完成后,用户有责任在适当的时间删除QNetworkReply对象。不要在连接到finished()的槽内直接删除它。可以使用deleteLater()函数。
- 注意:QNetworkAccessManager对它接收到的请求进行队列。并行执行的请求数量取决于协议。目前,对于桌面平台上的HTTP协议,一个主机/端口组合并行执行6个请求。
假设manager已经存在,下面是一个更复杂的例子:
QNetworkRequest request;
request.setUrl(QUrl("http://qt-project.org"));
request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");
QNetworkReply *reply = manager->get(request);
connect(reply, &QIODevice::readyRead, this, &MyClass::slotReadyRead);
connect(reply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error),
this, &MyClass::slotError);
connect(reply, &QNetworkReply::sslErrors,
this, &MyClass::slotSslErrors);
2. 上传数据
当然还可以使用 post(const QNetworkRequest &request, QIODevice *data) 方法 发送请求和数据
- post() 函数介绍:向request指定的目的地发送一个HTTP POST请求,并返回一个新的QNetworkReply对象,该对象打开以供读取,其中将包含服务器发送的应答。数据设备的内容将被上传到服务器。
数据必须打开以便读取,并且必须在finished()信号发出之前保持有效。
下面就是一个 上传数据到服务器的一个简单例子,QHttpMultiPart 其实就是上传MIME 数据的盒子,这个也就是上传附件之类的函数。下面就是上传一张图片和一段文本的样例。
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart textPart;
textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text\""));
textPart.setBody("my text");
QHttpPart imagePart;
imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"image\""));
QFile *file = new QFile("image.jpg");
file->open(QIODevice::ReadOnly);
imagePart.setBodyDevice(file);
file->setParent(multiPart); // we cannot delete the file now, so delete it with the multiPart
multiPart->append(textPart);
multiPart->append(imagePart);
QUrl url("http://my.server.tld");
QNetworkRequest request(url);
QNetworkAccessManager manager;
QNetworkReply *reply = manager.post(request, multiPart);
multiPart->setParent(reply); // delete the multiPart with the reply
// here connect signals etc.
同样还有就是用的 head() 方法,这个就是只交换头部数据,而不会传输body ,这个也是http协议的一部分。
二、网络和漫游支持
这个我用的很少,我暂时不太清楚。
随着Qt 4.7的承载管理API的增加,QNetworkAccessManager获得了管理网络连接的能力。如果设备离线,QNetworkAccessManager可以启动网络接口,如果当前进程是最后一个使用上行链路的进程,则终止该接口。请注意,有些平台从最后一个应用程序停止使用上行链路开始,一直到系统实际终止连接链路为止,都会使用宽限期。漫游同样透明。任何排队/待处理的网络请求都会自动转移到新的访问点。
想要利用这个特性的客户端不需要任何更改。事实上,很可能现有的特定于平台的连接代码可以简单地从应用程序中删除。
注意:QNetworkAccessManager的网络和漫游支持取决于支持连接管理的平台。QNetworkConfigurationManager::NetworkSessionRequired可用于检测QNetworkAccessManager是否利用此功能。