首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QML :QML请求握手失败

QML :QML请求握手失败
EN

Stack Overflow用户
提问于 2015-03-17 13:19:40
回答 1查看 1.7K关注 0票数 1

我直接从qml视图发出一些https请求,例如针对图像源。因为我有一个自签名的证书服务器端,所以我需要告诉qt忽略一些ssl错误(我控制服务器和客户端应用程序,所以这不应该是个问题)。

我制作了一个QQmlNetworkAccessManagerFactory来创建NAMs,在这里我连接到sslErrors信号。

UltraQmlAccessManagerFactory.h:

代码语言:javascript
复制
#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);
};

#endif

UltraQmlNetworkAccessManagerFactory.cpp:

代码语言:javascript
复制
#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文件中所看到的那样,我试图忽略接收到的每一个错误(作为测试),但是在输出中我没有得到预期的结果。

输出

代码语言:javascript
复制
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();,但是,这没有任何改变。

EN

回答 1

Stack Overflow用户

发布于 2021-09-06 12:43:05

(这是一个非常古老的问题,但由于我最近无意中发现了这个问题的答案,我认为仍然值得回答。)

您没有显示实际设置工厂对象的位置,但很可能它不属于调用其create()方法时使用的相同(实际上是任意)线程。以下是类的Qt文档的摘录

如果要从create()返回的对象的信号连接到可能在不同线程中创建的对象的槽,则开发人员应该小心。

它进一步提到了authenticationRequired()信号,但是sslErrors()的作用方式是相同的:这两个信号和其他信号都需要一个直接的或阻塞的排队连接,以便在返回到发出信号的位置时,网络应答对象已经由时隙配置。

在您的情况下发生的事情(很可能)如下(TL;DR:您的插槽由排队的连接异步调用,因为它驻留在不同的线程中,而sslErrors()需要对正在运行的网络应答对象进行同步更改;尽管有日志行的顺序,请求首先失败,ignoreSslErrors()随后被调用):

  1. 在主线程中创建工厂对象,并配置QML引擎。
  2. QML引擎生成几个线程来执行后端内容,特别是对URL的网络请求(我在这里假设您的ImageView.qml有一个Image组件)。为了执行网络请求,这些线程调用UltraQmlNetworkAccessManagerFactory::create()
  3. create()生成一个NAM对象并在其上设置一个连接。这里的父对象要么是QQmlEngine对象,要么(特别是用于图像请求的)后端线程对象,例如,这里。因此,这个NAM对象属于后端线程。
  4. connect()默认使用Qt::AutoConnection类型,因为工厂和NAM对象的线程是不同的,因此对应于Qt::QueuedConnection。作为sidenote,线程被检查在信号调用时
  5. 最终发出一个QNetworkAccessManager::sslErrors()信号。因为这是一个排队的连接,所以唯一立即发生的事情就是在主线程的事件队列上调用onIgnoreSslErrors()
  6. 如果你很幸运的话,你可能在那之后有一个上下文切换到主线程--但实际上没有什么可以确保这一点,所以控制返回到发出QNetworkAccessManager::sslErrors()的站点的可能性要大得多。由于没有调用ignoreSslErrors(),所以请求无法进行握手。后端线程在方法的中间调用 (或者稍后它可能会这么做--这已经不再重要了)。
  7. 当上下文切换到主线程ignoreSslErrors()时--唉,已经太晚了,因为网络回复很可能已经失败了;但是现在出现了第一个日志行。
  8. 主线程继续执行事件循环,并找到包含故障数据的QQuickPixmapReply::Event对象。在一些调用和信号展开后,失败的映像将在为您打印第二条日志行的中结束。

至于修复,很容易将Qt::BlockingQueuedConnection指定为connect()的第五个参数。不幸的是,如果从运行在主线程中的QQmlEngine发出请求,并且使用该工厂创建的NAM实例,例如,通过网络请求QML组件,这将导致死锁。到目前为止我所能做的就是

代码语言:javascript
复制
connect(nam, SIGNAL(sslErrors(QNetworkReply*, QList<QSslError>)),
        this, SLOT(onIgnoreSslErrors(QNetworkReply*,QList<QSslError>)),
        currentThread() == this->thread() ? Qt::DirectConnection
                                          : Qt::BlockingQueuedConnection
        );
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29100158

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档