Qt WebView - 拦截加载 JS/CSS 库以加载本地库

Qt WebView - intercept loading of JS/CSS Libraries to load local ones

我一直在通过文档寻找实现此目的的方法,但尚未成功。基本思想是,我有一块 html 通过 Qt 的 webview 加载。相同的内容可以导出到单个 html 文件。

此文件使用 Bootstrap 和 jQuery 等库。目前我通过 CDN 加载它们,在线时工作正常。但是,我的应用程序还需要 运行 离线。所以我正在寻找一种方法来拦截 Qt 中库的加载并改为提供本地保存的文件。我试过安装 https QWebEngineUrlSchemeHandler,但这似乎从未触发它的 requestStarted 方法。

(PyQT example follows)
QWebEngineProfile.defaultProfile().installUrlSchemeHandler(b'https', self)

如果我为该方案使用不同的文本并将其嵌入到页面中,那么我的假设是它不起作用,因为 Qt 已经为它注册了一个默认处理程序。但是这种不同的方案在文件导出时会失败。

不管怎样,回到核心问题;有没有办法拦截库的加载,或者仅在 Qt 中专门更改 url 方案?

进一步了解 QWebEngineUrlRequestInterceptor,现在将 https 请求重定向到我自己的 uri,它有一个 uri 处理程序。但是,请求永远不会通过它,因为:重定向位置 'conapp://webresource/bootstrap.min.css' 有一个不允许的跨源请求方案。 如何将我自己的 conapp uri 方案列入白名单?

编辑:为了完整起见,当我最初提出问题时,由于其中的错误,无法使用 PySide 5.11 完成。我当时报告的错误现在被标记为已修复(我相信是 5.12.1),所以现在应该可以使用 Qt 方法再次完成此操作,但是对于我自己的项目,我现在会坚持使用 jinja,它已成为一种解决方案对于许多其他问题。

下面的例子展示了我是如何做到的。它使用 QWebEngineUrlRequestInterceptor 将内容重定向到本地服务器。

举个例子,我截取了Whosebug的stacks.css,做了一个明显的改动。

import requests
import sys
import threading
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage, QWebEngineProfile
from PyQt5.QtWebEngineCore import QWebEngineUrlRequestInterceptor, QWebEngineUrlRequestInfo
from http.server import HTTPServer, SimpleHTTPRequestHandler
from socketserver import ThreadingMixIn

# Set these to the address you want your local patch server to run
HOST = '127.0.0.1'
PORT = 1235

class WebEngineUrlRequestInterceptor(QWebEngineUrlRequestInterceptor):
    def patch_css(self, url):
        print('patching', url)
        r = requests.get(url)
        new_css = r.text + '#mainbar {background-color: cyan;}'  # Example of some css change
        with open('local_stacks.css', 'w') as outfile:
            outfile.write(new_css)
    def interceptRequest(self, info: QWebEngineUrlRequestInfo):
        url = info.requestUrl().url()
        if url == "https://cdn.sstatic.net/Shared/stacks.css?v=596945d5421b":
            self.patch_css(url)
            print('Using local file for', url)
            info.redirect(QtCore.QUrl('http:{}:{}/local_stacks.css'.format(HOST, PORT)))

class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
    """Threaded HTTPServer"""

app = QtWidgets.QApplication(sys.argv)

# Start up thread to server patched content
server = ThreadingHTTPServer((HOST, PORT), SimpleHTTPRequestHandler)
server_thread = threading.Thread(target=server.serve_forever)
server_thread.daemon = True
server_thread.start()

# Install an interceptor to redirect to patched content
interceptor = WebEngineUrlRequestInterceptor()
profile = QWebEngineProfile.defaultProfile()
profile.setRequestInterceptor(interceptor)

w = QWebEngineView()
w.load(QtCore.QUrl('https://whosebug.com'))
w.show()
app.exec_()

所以,我最终采用的解决方案是,首先引入 jinja 模板。然后,使用这些模板将根据导出或内部使用设置变量和块,从那里我不再需要拦截器了。