在動手分析前,簡單介紹一下HTTP協定。HTTP協定是一種為分布式,合作式,超媒體資訊系統。它是一種通用的,無狀态(stateless)的協定,除了應用于超文本傳輸外,它也可以應用于諸如名稱伺服器和分布對象管理系統之類的系統,這可以通過擴充它的請求方法,錯誤代碼和報頭來實作。HTTP的一個特點是資料表現形式是可輸入的和可協商性的,這就允許系統能被建立而獨立于資料傳輸。HTTP在1990年WWW全球資訊剛剛起步的時候就得到了應用。該規範定義的協定用“HTTP/1.1”表示,是對RFC2608[33]的更新。
HTTP協定是通過定義一序列的動作(協定文本中稱為方法),來完成資料的傳輸通信。HTTP1.1版本中有這些方法:get、post、head、options、put、delete、trace、connect。
get方法用于擷取URI資源,是最為常用的一種方法。
post方法用于向指定URI送出内容,伺服器端響應其行為,該方法也極為常用。
head方法向URI發送請求,僅僅隻需要獲得響應的協定頭。
put方法用于向URI發送請求,若URI不存在,則要求伺服器端根據請求建立資源。當URI存在時,伺服器端必須接受請求内容,将其作為URI資源的修改後版本。
delete方法用于删除URI辨別的指定資源。
trace方法用于激活伺服器端對請求的循環回報,回報作為http響應的正文内容被傳輸回用戶端。
connect方法通常被用于使用代理連接配接。
更詳細的内容請檢視相關資料。
回到QT系統,manager->get()調用其實就是HTTP/1.1協定中get方法的實作。
QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request)
{
return d_func()->postProcess(createRequest(QNetworkAccessManager::GetOperation, request));
}
上面的一行程式中有兩個調用:
1、QNetworkAccessManager::createRequest()
2、QNetworkAccessManagerPrivate::postProcess()
先來看createRequest(),兩個參數:第一個參數表示使用Get方法;第二個參數是目标網址。
QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Operation op,
const QNetworkRequest &req,
QIODevice *outgoingData)
Q_D(QNetworkAccessManager);
QNetworkRequest request = req;
if (!request.header(QNetworkRequest::ContentLengthHeader).isValid() &&
outgoingData && !outgoingData->isSequential()) {
// request has no Content-Length
// but the data that is outgoing is random-access
request.setHeader(QNetworkRequest::ContentLengthHeader, outgoingData->size());
}
if (d->cookieJar) {
QList<QNetworkCookie> cookies = d->cookieJar->cookiesForUrl(request.url());
if (!cookies.isEmpty())
request.setHeader(QNetworkRequest::CookieHeader, qVariantFromValue(cookies));
// first step: create the reply
QUrl url = request.url();
QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
QNetworkReplyImplPrivate *priv = reply->d_func();
priv->manager = this;
// second step: fetch cached credentials
QNetworkAuthenticationCredential *cred = d->fetchCachedCredentials(url);
if (cred) {
url.setUserName(cred->user);
url.setPassword(cred->password);
priv->urlForLastAuthentication = url;
// third step: setup the reply
priv->setup(op, request, outgoingData);
#ifndef QT_NO_NETWORKPROXY
QList<QNetworkProxy> proxyList = d->queryProxy(QNetworkProxyQuery(request.url()));
priv->proxyList = proxyList;
#endif
// fourth step: find a backend
priv->backend = d->findBackend(op, request);
if (priv->backend) {
priv->backend->setParent(reply);
priv->backend->reply = priv;
#ifndef QT_NO_OPENSSL
reply->setSslConfiguration(request.sslConfiguration());
return reply;
代碼比較長,主要做了這些事情:
1、設定HTTP請求的頭資訊(例如用戶端請求内容的長度、Cookie等)
2、生成并初始化Reply對象(實際是QNetworkReplyImpl對象)
3、擷取本地緩存的認證資訊(如果有的話)
4、設定Reply
5、擷取一個backend實體
6、如果支援OPENSSL的話,設定SSL的配置
暫時先放一邊後面再對createRequest()做進一步的分析,再來看postProcess()
QNetworkReply *QNetworkAccessManagerPrivate::postProcess(QNetworkReply *reply)
Q_Q(QNetworkAccessManager);
QNetworkReplyPrivate::setManager(reply, q);
q->connect(reply, SIGNAL(finished()), SLOT(_q_replyFinished()));
/* In case we're compiled without SSL support, we don't have this signal and we need to
* avoid getting a connection error. */
q->connect(reply, SIGNAL(sslErrors(QList<QSslError>)), SLOT(_q_replySslErrors(QList<QSslError>)));
簡單來說就做了一件事情,把QNetworkReply的信号(finished、sslErrors)與QNetworkAccessManager的槽連接配接起來。