如何在 RequestInterceptor 中正确设置 QWebEngine HTTP 标头

5 qt header http python-3.x

我在 Python3 上遇到了 PyQt5 的 QWebEngineUrlRequestInterceptor 问题,更重要的是 setHttpHeader 函数。这是我的代码:

class WebEngineUrlRequestInterceptor(QWebEngineUrlRequestInterceptor):
def __init__(self, parent=None):
    super().__init__(parent)

def interceptRequest(self, info):
    info.setHttpHeader("X-Frame-Options", "ALLOWALL")
    print(info.requestUrl())
Run Code Online (Sandbox Code Playgroud)

不幸的是,使用此功能的正确方法似乎完全找不到,因此我不得不尝试我能想到的所有可能的方法,但无济于事。

我也尝试过使用 setHttpHeader 的参数QByteArray,这导致 QByteArray 给我这个抱怨......

    Traceback (most recent call last):
  File "test.py", line 30, in interceptRequest
    info.setHttpHeader(QByteArray("X-Frame-Options"), QByteArray("ALLOWALL"))
TypeError: arguments did not match any overloaded call:
  QByteArray(): too many arguments
  QByteArray(int, str): argument 1 has unexpected type 'str'
  QByteArray(Union[QByteArray, bytes, bytearray]): argument 1 has unexpected type 'str'
Run Code Online (Sandbox Code Playgroud)

.encode('ascii')我还尝试过使用和 甚至对字符串进行编码.encode('utf-8')。虽然两者都没有引发错误,但标头也拒绝更改,这使我相信返回的值与该函数不兼容。

更新:甚至QByteArray(b"X-Frame-Options")不设置标题。js: Refused to display 'https://www.google.co.uk/?gfe_rd=cr&dcr=0&ei=rX2gWtDJL8aN8Qfv3am4Bw' in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'.是我从 WebEngine 得到的错误。

需要补充的是,我 100% 确定interceptRequest正在调用。我可以print在终端中看到调用的输出。

完整的 MCVE 代码位于 [更新链接]:https ://paste.ee/p/Y0mRs

Tar*_*ani 5

首先,问题是为什么现有代码不起作用?

class WebEngineUrlRequestInterceptor(QWebEngineUrlRequestInterceptor):
    def __init__(self, parent=None):
        super().__init__(parent)

    def interceptRequest(self, info):
        info.setHttpHeader("X-Frame-Options", "ALLOWALL")
        print(info.requestUrl())
Run Code Online (Sandbox Code Playgroud)

现在,当您安装 a 时UrlRequestInterceptor,它绝对是一个请求拦截器。发起的请求WebEngineView都是通过这个传递的,你可以用它做很多事情

  • 一起更改 URL
  • 阻止其下载(广告拦截等...)
  • 添加更多标头以请求
  • 重定向到不同的网址

现在,当您有了 时info.setHttpHeader("X-Frame-Options", "ALLOWALL"),它会将其添加到请求中,而不是添加到响应中。可以通过将 url 更改为来验证这一点http://postman-echo.com/get,您将收到以下响应

{
  "args": {
    
  },
  "headers": {
    "host": "postman-echo.com",
    "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
    "accept-encoding": "gzip, deflate",
    "cookie": "sails.sid=s%3AXNukTzCE5ucYNEv_NB8ULCf4esVES3cW.%2BmpA77H2%2F%2B6YcnypvZ7I8RQFvVJrdOFs8GD%2FPymF0Eo",
    "if-none-match": "W/\"1e1-rYSDjZun8qsI1ZojoxMuVg\"",
    "upgrade-insecure-requests": "1",
    "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) QtWebEngine/5.10.1 Chrome/61.0.3163.140 Safari/537.36",
    "x-frame-options": "ALLOW",
    "x-forwarded-port": "80",
    "x-forwarded-proto": "http"
  },
  "url": "http://postman-echo.com/get"
}
Run Code Online (Sandbox Code Playgroud)

但响应端没有任何变化,您仍然拥有原始请求实际返回的任何内容。

可以QWebView安装QNetworkAccessManager并返回QNetworkReply修改后的响应。中显示的东西

如何将内容写入 QNetworkReply(是:带有生成内容的 QWebview)

但是如果您阅读了从 Qt WebKit 移植到 Qt WebEngine指南,就会发现有一个重要的区别需要注意

Qt WebEngine 不与 QNetworkAccessManager 交互

Qt Network 的某些类(例如 QAuthenticator)被重用于其接口,但与 Qt WebKit 不同,Qt WebEngine 有自己的 HTTP 实现,并且无法通过 QNetworkAccessManager。

仍然支持的 QNetworkAccessManager 信号和方法已移至 QWebEnginePage 类。

我挖了很多线程要求响应修改方法。不幸的是,一切都没有得到答复

使用 QWebEngineView 捕获服务器响应

QWebEngineView 在渲染之前修改网页内容

https://forum.qt.io/topic/81450/capture-client-request-headers-with-qwebengineview

使用QWebEngine拦截AJAX POST请求并读取数据?

所以这不是轻易就能实现的。但我认为有一种解决方法可行,但我还无法验证它

方法是添加一个新的schemeurl 处理程序

self.conn_handler = AppSchemeHandler()
self.profile.installUrlSchemeHandler("conapp".encode(), self.conn_handler)
self.webpage = MyQWebEnginePage(self.profile, self.view)
Run Code Online (Sandbox Code Playgroud)

现在我们更新拦截器,以便它修改 google url 以将请求重定向到我们的处理程序

class WebEngineUrlRequestInterceptor(QWebEngineUrlRequestInterceptor):
    def __init__(self, parent=None):
        super().__init__(parent)

    def interceptRequest(self, info):
        info.setHttpHeader(b'x-frame-options', b'ALLOW')
        print(info.requestUrl())

        if str(info.requestUrl().host()) == "google.com":
            url = info.requestUrl().toString()
            item = url.split("/")[-1]

            info.redirect(QUrl(r"conapp://webresource?url=" + url))
Run Code Online (Sandbox Code Playgroud)

然后在我们的方案处理程序中

class AppSchemeHandler(QWebEngineUrlSchemeHandler):
    def __init__(self, parent=None):
        super().__init__(parent)

    def requestStarted(self, request):
        url = request.requestUrl().toString().replace("conapp://webresource?url=", "")
        response = QWebEngineHttpRequest(QUrl(url))

        # Do something here which returns the response back to the url
Run Code Online (Sandbox Code Playgroud)

我们读取响应并将其发回的部分是我尚未在任何地方找到的示例