Qt Quick(Python)网络请求

接口请求

Qt PySide2自带的网络请求,使用起来不太方便。

个人更喜欢使用httpx进行网络请求。

https://www.psvmc.cn/article/2021-11-26-python-httpx.html

工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
from urllib.parse import urlencode

from PySide2.QtCore import QObject, Signal, Slot
from PySide2.QtNetwork import (QNetworkAccessManager, QNetworkRequest,
QSslSocket)

from utils.z_file_utils import file_to_base64


class NetworkManager(QObject):
dataReady = Signal(str, str) # 发出 (请求标识符, 数据)

def __init__(self, parent=None):
super().__init__()
supportsSsl = QSslSocket.supportsSsl()
print(f"supportsSsl:{supportsSsl}")
versionString = QSslSocket.sslLibraryBuildVersionString()
print(f"versionString:{versionString}")
self.manager = QNetworkAccessManager(self)
self.manager.finished.connect(self.on_request_finished)

def on_request_finished(self, reply):
if reply.error():
print("Error:", reply.errorString())
else:
request_id = reply.request().attribute(QNetworkRequest.User) # 获取请求标识符
data = reply.readAll().data().decode()
self.dataReady.emit(request_id, data)

@Slot(str, str)
def get_data(self, url, request_id):
request = QNetworkRequest(url)
request.setAttribute(QNetworkRequest.User, request_id) # 设置请求标识符
self.manager.get(request)

@Slot(str, str, str)
def post_data(self, request_id, url, data):
request = QNetworkRequest(url)
request.setAttribute(QNetworkRequest.User, request_id) # 设置请求标识符
request.setHeader(
QNetworkRequest.ContentTypeHeader,
"application/json"
)
self.manager.post(request, data.encode('utf-8'))

@Slot(str, str, str)
def post_form(self, request_id, url, data):
request = QNetworkRequest(url)
request.setAttribute(QNetworkRequest.User, request_id) # 设置请求标识符
request.setHeader(
QNetworkRequest.ContentTypeHeader,
"application/x-www-form-urlencoded"
)
self.manager.post(request, data.encode('utf-8'))

@Slot(str, str)
def upload_file(self, request_id, filepathStr):
base64Str = file_to_base64(filepathStr)
base64StrAll = f"data:image/png;base64,{base64Str}"
print(base64StrAll)
paras = {
"base64path": base64StrAll,
"savefolder": "test/20250102"
}

parasStr = urlencode(paras)
self.post_form(
request_id, "https://test.psvmc.cn/bs/base", parasStr)

注意

参数定义位dict,qml传入的对象是获取不到的,所以才用的字符串。

使用方式

1
2
3
4
from utils.z_api_manager import NetworkManager 

network_manager = NetworkManager(app)
engine.rootContext().setContextProperty("networkManager", network_manager)

qml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Component.onCompleted: {
let paras = {
"savefolder": "test/20250102"
};
let paraStr = CommonMethods.objToKeyValueString(paras);
networkManager.post_form("login_req", "https://test.psvmc.cn/bs/base", paraStr);
}

Connections {
function onDataReady(request_id, data) {
console.log("onDataReady");
console.log("request_id:", request_id);
console.log("data", data);
}

target: networkManager
}

TLS初始化失败

在使用Qt5.15.2请求https资源时遇到TLS初始化失败

qt.network.ssl: QSslSocket::connectToHostEncrypted: TLS initialization failed

原因

Qt本身是支持ssl的,但是因为法律原因?没有自带对应的dll。

解决方法包括检查并确保QT版本与libea32.dll和ssleay32.dll库版本一致,从QT安装目录的Tools文件夹中找到这两个文件,然后将其复制到应用程序的同级目录下,完成此操作后问题得以解决。

我们可以查看SSL是否支持,及对应版本

1
2
3
4
5
from PySide2.QtNetwork import (QNetworkAccessManager, QNetworkRequest,QSslSocket)
r1 = QSslSocket.supportsSsl()
print(f"r1:{r1}")
r2 = QSslSocket.sslLibraryBuildVersionString()
print(f"r2:{r2}")

我这里结果是

r1:False
r2:OpenSSL 1.1.1g 21 Apr 2020

下载后安装即可(注意要和程序的位数一致)

OpenSSL-1.1.1g_64位安装包.zip
https://pan.baidu.com/s/1JdjKpafN3qTPzZYRv5VtBQ?pwd=3732

注意

python是32位还是64位要和DLL的位数一致。

安装到第二个选项时:

image-20241231124642239

可以选择第一项这样就能直接使用了。

也可以选择第二项,再把DLL(libcrypto-1_1-x64.dlllibssl-1_1-x64.dll)放在运行环境中。

  • 如果用的是mingw,拷贝到QT编译器目录下即可(Qt\5.15.2\mingw81_64\bin)。
  • 如果使用的python就放在所用解析器的同级目录。