Qt-Function-QWebFrame->load()_01

本文详细解析了Qt中的QWebFrame的load()函数,包括其内部使用的QNetworkRequest和QUrl等关键概念,探讨了构造函数的作用以及如何确保加载的URL为绝对URI。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前面只发布了QWebView的代码,并没有具体的解释过load()函数。在这里补充上。

2012.10.19 于济南

先贴上两个load的源码,分别命名为load1、load2,方便下文论述:

load1:

void QWebFrame::load(const QUrl &url)
{
    // The load() overload ensures that the url is absolute.
    load(QNetworkRequest(url));
}

load2:

void QWebFrame::load(const QNetworkRequest &req,
                     QNetworkAccessManager::Operation operation,
                     const QByteArray &body)
{
    if (d->parentFrame())
        d->page->d->insideOpenCall = true;

    QUrl url = ensureAbsoluteUrl(req.url());

    WebCore::ResourceRequest request(url);

    switch (operation) {
        case QNetworkAccessManager::HeadOperation:
            request.setHTTPMethod("HEAD");
            break;
        case QNetworkAccessManager::GetOperation:
            request.setHTTPMethod("GET");
            break;
        case QNetworkAccessManager::PutOperation:
            request.setHTTPMethod("PUT");
            break;
        case QNetworkAccessManager::PostOperation:
            request.setHTTPMethod("POST");
            break;
        case QNetworkAccessManager::DeleteOperation:
            request.setHTTPMethod("DELETE");
            break;
        case QNetworkAccessManager::CustomOperation:
            request.setHTTPMethod(req.attribute(QNetworkRequest::CustomVerbAttribute).toByteArray().constData());
            break;
        case QNetworkAccessManager::UnknownOperation:
            // eh?
            break;
    }

    QVariant cacheLoad = req.attribute(QNetworkRequest::CacheLoadControlAttribute);
    if (cacheLoad.isValid()) {
        bool ok;
        uint cacheLoadValue = cacheLoad.toUInt(&ok);
        if (ok)
            request.setCachePolicy(cacheLoadControlToCachePolicy(cacheLoadValue));
    }

    QList<QByteArray> httpHeaders = req.rawHeaderList();
    for (int i = 0; i < httpHeaders.size(); ++i) {
        const QByteArray &headerName = httpHeaders.at(i);
        request.addHTTPHeaderField(QString::fromLatin1(headerName), QString::fromLatin1(req.rawHeader(headerName)));
    }

    if (!body.isEmpty())
        request.setHTTPBody(WebCore::FormData::create(body.constData(), body.size()));

    d->frame->loader()->load(request, false);

    if (d->parentFrame())
        d->page->d->insideOpenCall = false;
}

先看load1的内容。入口形参为const QUrl url,对于形参使用const定义,是为了在程序中不修改此形参的值,只使用此值,简单的说,这种形参就是输入参数,运行完此段程序,此形参的值并不发生变化。那么使用此url做了些什么呢?可以看到此函数只有一行,load(QNetworkRequest (url));,调用了此类(QWebFrame)中的一个load()函数。在C++中,可以根据入口形参类型及个数等自动匹配重载函数。那么我们需要知道这个入口形参的类型是否跟下面的load2的形参类型相同,也就是:这个load()是否就是调用的下文形参较多的那个load()。

为了查找实参类型,我们需要找到QNetworkRequest,位于src/network/access/目录中,qnetworkrequest.cpp。

QNetworkRequest::QNetworkRequest(const QUrl &url)
    : d(new QNetworkRequestPrivate)
{
    d->url = url;
}

QNetworkRequest::QNetworkRequest(const QNetworkRequest &other)
    : d(other.d)
{
}

可以看到,类QNetworkRequest有两个构造函数,重载了。对应于我们调用的这个,匹配的是第一种,入口形参为url的那个。

我们看到,第一个构造函数,自带初始化d = new QNetworkRequestPrivate。类QNetworkRequestPrivate是类QNetworkRequest的友元类,位于此cpp文件的上方,类的构造函数的定义放在了类的声明内部,看起来比较长。而d就是此类的一个实例,通过d的初始化可以看出来,也可以去qnetworkrequest_p.h中去看。此类中就定义了一个QUrl类型的url变量。所以就有了上述d->url = url;语句。

上面寻找qnetworkrequest的步骤比较多余。。。

我们知道,构造函数是没有返回类型的,那么通过构造函数,运行出来的是什么呢?其实对于load1,我们可以这样写:

QNetworkRequest *myInstance;
myInstance = new QNetworkRequest(url);
load(myInstance);

看出来了吧,构造函数运行出来的,就是这个类的实例,只不过没有具体的名字而已。通过这里,我们就可以看出了,load1的入口形参就是一个类型为QNetworkRequest的变量,正好对应于load2的第一个形参类型。我们知道,在C++中,实参的个数可以少于形参,前提是多出来的形参有默认的赋值,我们来看一下load2的声明:

void load(const QNetworkRequest &request,
              QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation,
              const QByteArray &body = QByteArray());

可以看到,除了第一个参数外,后面两个形参均已经赋了默认值,这样在调用的时候,后两个参数就可以省略不写了,符合C++的语法规范。

从上面的叙述中,我们就可以确定,load1中调用的load(),就是load2。下面我们只要分析load2就行了。

函数一开始,又出现了d,综合多个类(像QWebFrame、QWebPage、QNetworkRequest等)来看,d是每个类友元类(类名+Private)的实例,仅限类内部调用,私有,不是全局变量。例如在类QWebFrame中,调用QWebPagePrivate的d,需要:d->page->d->...,其中page是QWebFrame中的成员变量,类型为QWebPage。关于这里出现的if操作,就先跳过了。

语句:QUrl url = ensureAbsoluteUrl(req.url());

先看这个函数ensureAbsoluteUrl(),字面意思可以看出:确保绝对Url。这需要先了解一下http协议的知识。http/1.1 中规定,浏览器所请求资源(URL)的确定可以有四种方式,其中一种就是由Request-URI直接确定,叫做绝对URI。看看这两者之间是否有联系。F2找到函数定义:

static inline QUrl ensureAbsoluteUrl(const QUrl &url)
{
    if (!url.isValid() || !url.isRelative())
        return url;

    // This contains the URL with absolute path but without 
    // the query and the fragment part.
    QUrl baseUrl = QUrl::fromLocalFile(QFileInfo(url.toLocalFile()).absoluteFilePath()); 

    // The path is removed so the query and the fragment parts are there.
    QString pathRemoved = url.toString(QUrl::RemovePath);
    QUrl toResolve(pathRemoved);
    
    return baseUrl.resolved(toResolve);
}

这个函数的作用是:如果url不是relative的(relative就是没有http://的网址),则返回此url;换句话说,如果url是绝对的(absolute),则不对此url做其他操作,直接返回此url。至于valid与下面的其他操作暂时先不讨论,目测就是没有http时就给加上。

再看load2的下一条语句:

WebCore::ResourceRequest request(url);

需要找到这个类,位置:src\3rdparty\webkit\Source\WebCore\platform\network\qt\ResourceRequest.h。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值