Qt 5.7 QNetworkProxy 不考虑 cookie
Posted
技术标签:
【中文标题】Qt 5.7 QNetworkProxy 不考虑 cookie【英文标题】:Qt 5.7 QNetworkProxy does not take into account cookies 【发布时间】:2017-01-06 12:25:49 【问题描述】:我正在开发一个使用 QWebEngineView 和 QNetworkAccessManager 的 Qt 云客户端应用程序。我遇到的问题描述如下:
应用程序有一个自定义登录表单。根据用户凭据,我执行一系列手动请求(“post”和“get”)来获取相关的会话 cookie。
...
//get session cookie
QNetworkAccessManager accessManager;
connect(&accessManager, &QNetworkAccessManager::proxyAuthenticationRequired, [=] (const QNetworkProxy &proxy, QAuthenticator *authenticator)
//perform proxy auth in case a proxy is set
);
QNetworkReply * reply = Q_NULLPTR;
QNetworkRequest request(QUrl(/*url*/));
request.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
request.setRawHeader("Cache-Control", "no-cache");
QByteArray data(/*data for auth*/);
reply = accessManager.post(request,data); //ajax login
QEventLoop waitReplyHandler;
QObject::connect(reply, SIGNAL(finished()), &waitReplyHandler, SLOT(quit()));
//wait for reply from url
waitReplyHandler.exec();
QVariant sessionCookie = reply->header(QNetworkRequest::SetCookieHeader); //this cookie is used to retrieve second "session cookie"
...
//Different function - get user session cookie
QNetworkRequest request(QUrl(/*url*/));
request.setHeader(QNetworkRequest::CookieHeader, sessionCookie);
QNetworkReply * reply = accessManager.get(request);
QEventLoop waitReplyHandler;
QObject::connect(reply, SIGNAL(finished()), &waitReplyHandler, SLOT(quit()));
//wait for reply from url
waitReplyHandler.exec();
QString redirect = reply->header(QNetworkRequest::LocationHeader).toString();
QVariant userSessionCookie = reply->header(QNetworkRequest::SetCookieHeader);
之后我为 QWebEngineView 设置了一个请求拦截器:
interceptor = new CWebEngineUrlRequestInterceptor(sessionCookie.value<QList<QNetworkCookie>>().first(),
userSessionCookie.value<QList<QNetworkCookie>>().first(),
this);
m_tabWebview->webEngineView()->page()->profile()->setRequestInterceptor(interceptor);
m_tabWebview->webEngineView()->load(redirectUrl); //Obtained from "redirect" string variable from second manual request
这个想法是使用这些手动获取的 cookie 来处理对 Web 引擎视图的每次加载调用:
void CWebEngineUrlRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo &info)
QByteArray sessionCookie = QByteArray(m_sessionCookie.name() + "=" + m_sessionCookie.value());
QByteArray userSessionCookie = QByteArray(m_userSessionCookie.name() + "=" + m_userSessionCookie.value());
QByteArray requestCookies = sessionCookie + "; " + userSessionCookie;
info.setHttpHeader(QByteArray("Cookie"), requestCookies);
这个工作完全没问题,在加载到redirectUrl之后,web视图将显示用户已经登录的云主页。但是,如果我为应用程序设置了一个QNetworkProxy:
QNetworkProxy proxy;
proxy.setType(QNetworkProxy::HttpProxy);
proxy.setHostName(proxyUrl);
proxy.setPort(proxyPort.toInt());
QNetworkProxy::setApplicationProxy(proxy);
以上序列将在 web 视图中显示我的目标 url 的登录页面。我相信应用程序级别的代理设置应该与 QWebEngineView 无关。手动请求正在工作,我能够获取cookies,也调用了interceptRequest,但是代理中继后cookies没有保留。 我还尝试手动将标头设置为代理自身:
QByteArray requestCookies = m_cookies.first().name() + "=" + m_cookies.first().value() + "; " +
m_cookies.last().name() + "=" + m_cookies.last().value();
QNetworkProxy proxy(QNetworkProxy::applicationProxy());
proxy.setRawHeader(QByteArray("Cookie"), requestCookies);
QNetworkProxy::setApplicationProxy(proxy);
//...
//check headers are set to proxy
QByteArray cookieVar = QNetworkProxy::applicationProxy().rawHeader(QByteArray("Cookie"));
if(cookieVar.isEmpty())
std::cout<<"empty cookies to proxy ";
else
std::cout<<cookieVar.toStdString()<<std::endl;
日志没问题,我可以看到 cookie 已附加到代理。
实现此自定义登录机制是为了在超过会话 cookie 的过期时间没有互联网连接的情况下处理自动登录。 如何设置应用级代理以使用手动获取的会话 cookie?
提前谢谢你。
【问题讨论】:
【参考方案1】:这似乎是与代理身份验证机制相关的Web引擎框架中的一个错误。但是我找到了一种解决方法: 调用 QWebEnginePage::proxyAuthenticationRequired 时,在设置了验证器对象的数据后,我只是再次调用 load 到 requestUrl 参数。
connect(app->webview()->page(), &QWebEnginePage::proxyAuthenticationRequired, [=] (const QUrl &requestUrl, QAuthenticator *authenticator, const QString &proxyHost)
proxyAuthSequence(authenticator, proxyHost);
app->webview()->load(requestUrl);
);
想法是将初始加载视为虚拟加载,仅设置身份验证数据,然后再次加载url。随后的加载调用将不再触发此信号。所以,基本上问题出在身份验证机制上。
这个 bug 也提交给了 Qt: https://bugreports.qt.io/browse/QTBUG-58121
【讨论】:
以上是关于Qt 5.7 QNetworkProxy 不考虑 cookie的主要内容,如果未能解决你的问题,请参考以下文章
如何测试 Qt4 应用程序的正确 QNetworkProxy 工作?
Qt文档阅读笔记-QNetworkProxy::ProxyType解析(Qt设置Fiddler代理)
Qt文档阅读笔记-QNetworkProxy::ProxyType解析(Qt设置Fiddler代理)
Qt 4.8.4 Cross-Compiled for Embedded Linux 失败并出现 QNetworkProxy 错误