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

时间:2018-03-07 23:44:28

标签: python-3.x qt http header

我在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())

不幸的是,使用这个函数的正确方法似乎绝对无处可去,因此我不得不求助于尝试我能想到的所有可能方法,但无济于事。

我也尝试用QByteArray包围setHttpHeader的参数,这导致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'

我还尝试使用.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

1 个答案:

答案 0 :(得分:3)

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

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

    def interceptRequest(self, info):
        info.setHttpHeader("X-Frame-Options", "ALLOWALL")
        print(info.requestUrl())

现在,当您安装UrlRequestInterceptor时,它无论如何都是请求拦截器。由WebEngineView发起的请求通过此传递,您可以使用它做很多事情

  • 一起更改网址
  • 阻止其下载(AdBlocking等...)
  • 添加更多标题以供请求
  • 重定向到其他网址

现在,当您拥有info.setHttpHeader("X-Frame-Options", "ALLOWALL")时,它会将其添加到请求中而不是响应中。这可以通过将网址更改为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"
}

但是在响应方面没有任何改变,你仍然拥有原始请求实际返回的内容。

使用QWebView,可以安装QNetworkAccessManager并返回带有修改后回复的QNetworkReply

中显示的内容

How to write content to QNetworkReply (was: QWebview with generated content)

但是,如果您阅读了Porting from Qt WebKit to Qt WebEngine指南,则需要注意一个重要的区别

  

Qt WebEngine不与QNetworkAccessManager交互

     

某些Qt网络类如QAuthenticator被重用于它们的接口,但与Qt WebKit不同,Qt WebEngine有自己的HTTP实现,无法通过QNetworkAccessManager。

     

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

我挖了许多线程,要求采用响应修改方法。不幸的是,所有人都没有回答

Capture server response with QWebEngineView

QWebEngineView modify web content before render

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

Intercept AJAX POST request and read data using QWebEngine?

所以这不容易。但是我认为有一种解决方法可行,但我无法验证它

方法是添加新的scheme网址处理程序

self.conn_handler = AppSchemeHandler()
self.profile.installUrlSchemeHandler("conapp".encode(), self.conn_handler)
self.webpage = MyQWebEnginePage(self.profile, self.view)

现在我们更新拦截器,以便修改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))

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

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

我们阅读回复并将其发回的部分是我还没有找到任何地方的例子