使用 wrld.js 时出现 QWebEngineView “Access-Control-Allow-Headers”错误

Posted

技术标签:

【中文标题】使用 wrld.js 时出现 QWebEngineView “Access-Control-Allow-Headers”错误【英文标题】:QWebEngineView "Access-Control-Allow-Headers" error while using wrld.js 【发布时间】:2019-07-01 19:19:18 【问题描述】:

我想使用 Qt5 C++ 在 QWebEngineView 中通过 html/CSS/JS 显示地图。

它已经适用于传单 (https://leafletjs.com/): 如您所见,该窗口显示了在给定位置带有标记的地图。

但是尝试使用基于传单的 3D 地图 wrld (https://github.com/wrld3d/wrld.js),我只得到一个黑色窗口: 此外,命令行上还会显示以下错误/警告:

js: Refused to set unsafe header "Content-length"
js: Refused to set unsafe header "Connection"
js: Failed to load qrc://webgl-cdn1.eegeo.com/art_edits/continuous/incremental/us/sf/251/Ground/0/1/1/3/1/2/3/2/1/2/3/1/1/3/Ground.hcff?appinfo=Undefined%1Fb37aeaf9b6cd7eb5bc303d144af98ad0%1F1879%1Fd2cae54f44447344cfb3802d9365c03c3aa35e47%1FUndefined%1FUndefined%1Fjavascript%1FUndefined%1FUndefined%1FJavascript: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
js: Uncaught abort() at Error
    at Sa (https://cdn-webgl.wrld3d.com/eegeojs/public/v1879/eeGeoWebGL.jgz:63:124)
    at Ra (https://cdn-webgl.wrld3d.com/eegeojs/public/v1879/eeGeoWebGL.jgz:63:22)
    at Object.q [as abort] (https://cdn-webgl.wrld3d.com/eegeojs/public/v1879/eeGeoWebGL.jgz:410:102)
    at _abort (https://cdn-webgl.wrld3d.com/eegeojs/public/v1879/eeGeoWebGL.jgz:257:368)
    at Rh (https://cdn-webgl.wrld3d.com/eegeojs/public/v1879/eeGeoWebGL.jgz:275:40424)
    at or (https://cdn-webgl.wrld3d.com/eegeojs/public/v1879/eeGeoWebGL.jgz:275:389787)
    at pgc (https://cdn-webgl.wrld3d.com/eegeojs/public/v1879/eeGeoWebGL.jgz:283:389489)
    at ogc (https://cdn-webgl.wrld3d.com/eegeojs/public/v1879/eeGeoWebGL.jgz:283:389037)
    at ldc (https://cdn-webgl.wrld3d.com/eegeojs/public/v1879/eeGeoWebGL.jgz:283:298507)
    at kdc (https://cdn-webgl.wrld3d.com/eegeojs/public/v1879/eeGeoWebGL.jgz:283:296713)
If this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.

据我所知,这与响应标头中缺少标签有关(Access-Control-Allow-Headers),但我无法使其正常工作。我已经尝试通过 QWebEngineUrlRequestInterceptor 注入这些标头,但没有成功。

这是一个最小的“工作”示例:

main.cpp:

#include <QApplication>
#include <QWebEngineView>

int main(int argc, char** argv) 
  qputenv("QT_STYLE_OVERRIDE", "Fusion");
  QApplication app(argc, argv);

  QWebEngineView* mapview = new QWebEngineView();
  mapview->load(QUrl("qrc:/map.html"));
  mapview->show();

  app.exec();

  return 0;

map.html:(您需要https://www.wrld3d.com/ 的api 密钥才能使用wrld 版本)

<!doctype html>
<html lang="de">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.5.1/dist/leaflet.css"
    integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
    crossorigin=""/>

    <!-- comment in for the leaflet version -->
    <!-- <script src="https://unpkg.com/leaflet@1.5.1/dist/leaflet.js"
        integrity="sha512-GffPMF3RvMeYyc1LWMHtK8EbPv0iNZ8/oTtHPx9/cc2ILxQ+u905qIwdpULaqDkyBKgOaB57QTMg7ztg8Jm2Og=="
        crossorigin=""></script> -->

    <!-- wrld version -> not working -->
    <script src="https://cdn-webgl.wrld3d.com/wrldjs/dist/latest/wrld.js"></script>

</head>
<body>

<div id="mapid" style="width: 95vw; height: 95vh;"></div>
<script type="application/javascript">
    // comment in for the leaflet version
    // var map = L.map('mapid').setView([51.505, -0.09], 13);
    // L.tileLayer('http://s.tile.openstreetmap.org/z/x/y.png', 
    //   maxZoom: 18,
    //   attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
    //   '<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
    //   'Imagery © <a href="http://www.openstreetmap.org/#map=6/51.">OpenStreetMap</a>',
    //   id: 'mapbox.streets'
    // ).addTo(map);

    var map = L.Wrld.map("mapid", "PUT_YOUR_API_KEY_HERE");
</script>
</body>
</html>

resources.qrc:

<!DOCTYPE RCC><RCC version="1.0">
<qresource>
    <file>map.html</file>
</qresource>
</RCC>

CMakeLists.txt:

project (PROJ LANGUAGES CXX)

cmake_minimum_required (VERSION 3.9)

# set compiler flags for better warnings
add_compile_options(-Wall -Wextra -pedantic)


# set the required c++ standard to c++20
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 11)

# find Qt5
find_package(Qt5 REQUIRED Network WebEngine Widgets WebEngineWidgets)
qt5_add_resources(RCC_SOURCES resources.qrc)


# create executable with main file
add_executable(prog $CMAKE_CURRENT_SOURCE_DIR/main.cpp $RCC_SOURCES)
target_link_libraries(prog Qt5::Widgets Qt5::WebEngine Qt5::Network Qt5::WebEngineWidgets)

要运行该示例,请将所有四个文件放在一个目录中并使用 cmake/make 编译所有内容。

所需的输出应如下所示:

Qt 的 QWebEngineView 可以实现吗? 传单工作正常。 这就是我认为它不应该与 wrld 一起使用的真正原因。

【问题讨论】:

【参考方案1】:

这不是 Qt 错误,而是 wrld.js 错误,如 this discussion 中所述。从该转换可以得出结论,该库仅支持 http 或 https,而不支持其他方案。

因此解决方案是通过 HTTP 服务器启动 html,有多种选择,但假设您只想使用 Qt,那么我们可以利用以下模块:Qt HTTP server。要安装它,您必须执行以下步骤:

git clone --recursive https://codereview.qt-project.org/qt-labs/qthttpserver
cd qthttpserver
qmake
make
sudo make install

之后你必须将main.cpp修改为:

#include <QApplication>
#include <QWebEngineView>
#include <QHttpServer>

int main(int argc, char** argv) 
    qputenv("QT_STYLE_OVERRIDE", "Fusion");
    QApplication app(argc, argv);

    QHttpServer httpServer;
    httpServer.route("/", []() 
        return QHttpServerResponse::fromFile(QStringLiteral(":/map.html"));
    );

    const auto port = httpServer.listen(QHostAddress::Any);
    if (port == -1) 
        qDebug() << QStringLiteral("Could not run on http://127.0.0.1:%1/").arg(port);
        return 0;
    

    QWebEngineView view;
    view.load(QUrl(QStringLiteral("http://127.0.0.1:%1/").arg(port)));
    view.show();

    return app.exec();

还有 CMakeLists.txt:

project (PROJ LANGUAGES CXX)

cmake_minimum_required (VERSION 3.9)

# set compiler flags for better warnings
add_compile_options(-Wall -Wextra -pedantic)


# set the required c++ standard to c++20
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 11)

# find Qt5
find_package(Qt5 REQUIRED Network WebEngine Widgets WebEngineWidgets HttpServer)
qt5_add_resources(RCC_SOURCES resources.qrc)


# create executable with main file
add_executable(prog $CMAKE_CURRENT_SOURCE_DIR/main.cpp $RCC_SOURCES)
target_link_libraries(prog Qt5::Widgets Qt5::WebEngine Qt5::Network Qt5::WebEngineWidgets Qt5::HttpServer)

导致:

【讨论】:

感谢您的快速回复。不幸的是,我无法让 qthttpserver 正常工作。我克隆了那个 git repo,但是我不能运行 make(因为没有 make 文件)。所以我尝试了 qmake -project -> qmake -> make 但是 make 失败并输出:“src/httpserver/qabstracthttpserver.cpp:30:46: fatal error: QtHttpServer/qabstracthttpserver.h: No such file or directory 编译终止。” . @Arkantos493 不要把所有编译Qt Http服务器的命令都放上去,现在我已经改正了,试试看 不行,谢谢。主要问题是 qmake 使用了错误的 Qt 版本。 对不起,另一个愚蠢的问题,但如果 map.html 位于子目录中,我怎样才能让你的代码工作?例如在资源文件夹中?简单地将 ":/map.html" 更改为 ":/resources/map.html" 根本不起作用。

以上是关于使用 wrld.js 时出现 QWebEngineView “Access-Control-Allow-Headers”错误的主要内容,如果未能解决你的问题,请参考以下文章

使用 Qt5 的 QWebEngine

Qt 5.7:使用无头 QWebEngine

QWebEngine:同步执行 runJavascript - QEventLoop 阻止 Javascript 调用

QWebEngine 默认阻碍 github 导航

使用固定的内部命令参数运行脚本以包含 Qwebengine pepflashplayer

Qt QWebEngine - 使用 HTML <a> 锚点