我直接从qml视图发出一些https请求,例如针对图像源。因为我有一个自签名的证书服务器端,所以我需要告诉qt忽略一些ssl错误(我控制服务器和客户端应用程序,所以这不应该是个问题)。
我制作了一个QQmlNetworkAccessManagerFactory来创建NAMs,在这里我连接到sslErrors信号。
UltraQmlAccessManagerFactory.h:
#ifndef FACKFACKTORy_H
#define FACKFACKTORy_H
#include <QQmlNetworkAccessManagerFactory>
#include <QObject>
#include <QNetworkReply>
#include <QList>
#include <QSslError>
#include <QNetworkAccessManager>
#include <QDebug>
#include <QSslCertificate>
class UltraQmlNetworkAccessManagerFactory : public QObject,
public QQmlNetworkAccessManagerFactory {
Q_OBJECT
private:
QNetworkAccessManager* nam;
QList<QSslError> expectedSslErrors;
public:
explicit UltraQmlNetworkAccessManagerFactory();
~UltraQmlNetworkAccessManagerFactory();
virtual QNetworkAccessManager* create(QObject* parent);
public slots:
void onIgnoreSslErrors(QNetworkReply* reply, QList<QSslError> errors);
};
#endifUltraQmlNetworkAccessManagerFactory.cpp:
#include "UltraQmlNetworkAccessManagerFactory.h"
UltraQmlNetworkAccessManagerFactory::UltraQmlNetworkAccessManagerFactory() {
}
UltraQmlNetworkAccessManagerFactory::~UltraQmlNetworkAccessManagerFactory() {
delete nam;
}
QNetworkAccessManager* UltraQmlNetworkAccessManagerFactory::create(QObject* parent) {
QNetworkAccessManager* nam = new QNetworkAccessManager(parent);
QObject::connect(nam, SIGNAL(sslErrors(QNetworkReply*, QList<QSslError>)),
this, SLOT(onIgnoreSslErrors(QNetworkReply*,QList<QSslError>))
);
return nam;
}
void UltraQmlNetworkAccessManagerFactory::onIgnoreSslErrors(QNetworkReply *reply, QList<QSslError> errors) {
for (int i = 0; i < errors.size(); i++) {
qDebug() << "e: " << errors.at(i) << endl;
}
reply->ignoreSslErrors(errors);
}main.cpp中也有一些胶水将这个工厂设置为要使用的,我怀疑部分是否是错误的来源,因为qDebug打印在输出中是可见的。
正如在函数/插槽onIgnoreSslErrors中的onIgnoreSslErrors文件中所看到的那样,我试图忽略接收到的每一个错误(作为测试),但是在输出中我没有得到预期的结果。
输出
e: "The certificate is self-signed, and untrusted"
qrc:/qml/file/ImageView.qml:16:5: QML Image: SSL handshake failed我已经成功地使用一个QNetworkRequests直接从C++生成了TLSV1_0,指定了TLSV1_0和证书。由于我怀疑握手失败是因为一方期望SSL,而另一方期望TLS,因此我还试图通过QSslConfiguration设置QNetworkRequest对象上的reply->request();,但是,这没有任何改变。
发布于 2021-09-06 12:43:05
(这是一个非常古老的问题,但由于我最近无意中发现了这个问题的答案,我认为仍然值得回答。)
您没有显示实际设置工厂对象的位置,但很可能它不属于调用其create()方法时使用的相同(实际上是任意)线程。以下是类的Qt文档的摘录
如果要从create()返回的对象的信号连接到可能在不同线程中创建的对象的槽,则开发人员应该小心。
它进一步提到了authenticationRequired()信号,但是sslErrors()的作用方式是相同的:这两个信号和其他信号都需要一个直接的或阻塞的排队连接,以便在返回到发出信号的位置时,网络应答对象已经由时隙配置。
在您的情况下发生的事情(很可能)如下(TL;DR:您的插槽由排队的连接异步调用,因为它驻留在不同的线程中,而sslErrors()需要对正在运行的网络应答对象进行同步更改;尽管有日志行的顺序,请求首先失败,ignoreSslErrors()随后被调用):
ImageView.qml有一个Image组件)。为了执行网络请求,这些线程调用UltraQmlNetworkAccessManagerFactory::create()。create()生成一个NAM对象并在其上设置一个连接。这里的父对象要么是QQmlEngine对象,要么(特别是用于图像请求的)后端线程对象,例如,这里。因此,这个NAM对象属于后端线程。connect()默认使用Qt::AutoConnection类型,因为工厂和NAM对象的线程是不同的,因此对应于Qt::QueuedConnection。作为sidenote,线程被检查在信号调用时。QNetworkAccessManager::sslErrors()信号。因为这是一个排队的连接,所以唯一立即发生的事情就是在主线程的事件队列上调用onIgnoreSslErrors()。QNetworkAccessManager::sslErrors()的站点的可能性要大得多。由于没有调用ignoreSslErrors(),所以请求无法进行握手。后端线程在方法的中间调用 (或者稍后它可能会这么做--这已经不再重要了)。ignoreSslErrors()时--唉,已经太晚了,因为网络回复很可能已经失败了;但是现在出现了第一个日志行。QQuickPixmapReply::Event对象。在一些调用和信号展开后,失败的映像将在为您打印第二条日志行的中结束。至于修复,很容易将Qt::BlockingQueuedConnection指定为connect()的第五个参数。不幸的是,如果从运行在主线程中的QQmlEngine发出请求,并且使用该工厂创建的NAM实例,例如,通过网络请求QML组件,这将导致死锁。到目前为止我所能做的就是
connect(nam, SIGNAL(sslErrors(QNetworkReply*, QList<QSslError>)),
this, SLOT(onIgnoreSslErrors(QNetworkReply*,QList<QSslError>)),
currentThread() == this->thread() ? Qt::DirectConnection
: Qt::BlockingQueuedConnection
);https://stackoverflow.com/questions/29100158
复制相似问题