QWebView作为QT中自带的浏览器控件,使用简单方便,而功能强大。并且很容易通过扩展实现一些定制化需求。
实际业务中遇到一个需求:需要加载某个网页,待用户选择表单选项并提交之后,拦截HTTP请求,获取其Post数据,加以修改 后重新提交请这求。
查阅QT的官方文档,并没有找到相关功能可以实现,而网上这方面的资料也是少之又少,所以特意整理出来方便大家。
注意事项:
QWebView只在QT5.5以下的版本中存在,在QT5.6之上的版本中已经被QWebEngineView取代。
另外,QT的MINGW版本中也没有webenginewidgets模块,需要自己编译MSVC版本自带此模块。
示例中使用QT版本号:Qt 5.5.1 (MSVC 2013, 32 bit)
几个主要函数:
void QWebPage::setNetworkAccessManager(QNetworkAccessManager * manager)
Sets the QNetworkAccessManager manager responsible for serving network requests for this QWebPage.
Note: It is currently not supported to change the network access manager after the QWebPage has used it. The results of doing this are undefined.
See also networkAccessManager().
通过这个函数将manager设置成我们自己子类化之后的QNetworkAccessManager,方便拦截。
QNetworkReply * QNetworkAccessManager::createRequest(Operation op, const QNetworkRequest & req, QIODevice * outgoingData = 0)
Returns a new QNetworkReply object to handle the operation op and request req. The device outgoingData is always 0 for Get and Head requests, but is the value passed to post() and put() in those operations (the QByteArray variants will pass a QBuffer object).
The default implementation calls QNetworkCookieJar::cookiesForUrl() on the cookie jar set with setCookieJar() to obtain the cookies to be sent to the remote server.
The returned object must be in an open state.
通过重写此子类化函数,我们在自己的子类化的类中既可以获取到我们想要的内容。
此函数的三个参数:
参数1:OPeration op是一个枚举类型,对应定义值如下:
我们想要的post请求对应的op=4.
参数2:QNetWorkRequest& req.请求对象,包含URL,设置的其他head选项。
参数3:QIODevice* outgongingData 。这个参数只有当是post或者put请求时才有内容,其他情况下值为0.
以登陆百度账户为例:
在调试窗口可看到拦截的内容:
代码:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include
#include
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QWebView* m_pWebView;
QWidget *centralWidget;
QVBoxLayout *verticalLayout_2;
QVBoxLayout *verticalLayout;
QMenuBar *menuBar;
QToolBar *mainToolBar;
QStatusBar *statusBar;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
m_pWebView = new QWebView(this);
QNetworkAccessManager *oldManager = m_pWebView->page()->networkAccessManager();
MNetworkAccessManager *newManager = new MNetworkAccessManager(oldManager, this);
m_pWebView->page()->setNetworkAccessManager(newManager);
m_pWebView->page()->setForwardUnsupportedContent(true);
m_pWebView->load(QUrl("https://www.baidu.com/"));
this->setCentralWidget(m_pWebView);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
}
#ifndef MNETWORKACCESSMANAGER_H
#define MNETWORKACCESSMANAGER_H
#include
#include
#include
#include
#include
class MNetworkAccessManager : public QNetworkAccessManager
{
Q_OBJECT
public:
explicit MNetworkAccessManager(QNetworkAccessManager *manager, QObject *parent);
protected:
QNetworkReply * createRequest(QNetworkAccessManager::Operation operation,
const QNetworkRequest &request, QIODevice *device);
};
#endif // MNETWORKACCESSMANAGER_H
#include "mnetworkaccessmanager.h"
#include "QDebug"
#include
MNetworkAccessManager::MNetworkAccessManager(QNetworkAccessManager *manager, QObject *parent)
{
setCache(manager->cache());
setCookieJar(manager->cookieJar());
setProxy(manager->proxy());
setProxyFactory(manager->proxyFactory());
}
QNetworkReply *MNetworkAccessManager::createRequest(QNetworkAccessManager::Operation operation, const QNetworkRequest &request, QIODevice *device)
{
if(device)
{
qDebug()<<(int)operation<readAll();
//这里读取过之后 QIODevice 就不管用了,要重新设置,不然网站接收不到请求
QByteArray bytes=device->readAll();
qDebug()<setData(bytes);
return QNetworkAccessManager::createRequest(operation, request, pDeVice);
}
else
{
return QNetworkAccessManager::createRequest(operation, request, device);
}
}
参考:
https://blog.csdn.net/davidsu33/article/details/51058905
完整工程:https://download.csdn.net/download/lacoucou/10440360