目录
  • 1. 概述
  • 2. 详论
    • 2.1. 传参
    • 2.2. JS module
  • 3. 建议
    • 4. 参考

      1. 概述

      浏览器直接加载本地网页的时候,如果网页涉及到加载本地资源(如图片),会出现跨域的问题。Qt的Qt WebEngine模块基于Chromium项目,遇到这样的情况也会出现跨域的问题。

      2. 详论

      2.1. 传参

      理论上,我们可以像设置chrome浏览器跨域一样(设置chrome浏览器跨域网上的资料非常多),给我们使用的Qt程序传参:

      char ARG_DISABLE_WEB_SECURITY[] = "--disable-web-security";
      int newArgc = argc+1+1;
      char** newArgv = new char*[newArgc];
      for(int i=0; i<argc; i++) {
          newArgv[i] = argv[i];
      }
      newArgv[argc] = ARG_DISABLE_WEB_SECURITY;
      newArgv[argc+1] = nullptr;
      
      QApplication myApplication(newArgc, newArgv);
      

      Qt会将跨域参数传递到Qt WebEngine模块的Chromium内核中,从而实现跨域。

      2.2. JS module

      即使设置跨域,当使用JavaScript ES6 module的时候,仍然有可能会出现跨域的问题。

      一个显而易见的错误提示如下:

      js: Failed to load module script: The server responded with a non-JavaScript MIME type of "". Strict MIME type checking is enforced for module scripts per HTML spec.

      原因在于,在Chrome浏览器的某些版本中,ES6 module的功能不支持跨域(但是require.js却可以)。现在最新版本的Chrome的跨域设置已经可以支持ES6 module,但是Qt WebEngine模块却可能是比较低的Chromium版本,从而造成使用ES6 module遇到跨域问题。通常来说,越新的Qt版本,Chromium版本也会越高。

      如果还是不想要服务器环境,那么一种解决方案就是自定义URL方案:

      #include <QApplication>
      #include <QWebEngineView>
      #include <QWebEngineUrlScheme>
      #include <QWebEngineProfile>
      #include <QWebEngineUrlSchemeHandler>
      #include <QWebEngineUrlRequestJob>
      #include <QFile>
      #include <QFile>
      #include <QFileInfo>
      #include <QMimeDatabase>
      
      class QtSchemeHandler : public QWebEngineUrlSchemeHandler
      {
      public:
          QtSchemeHandler(QObject *parent = nullptr):QWebEngineUrlSchemeHandler(parent)
          {
          }
      
          void requestStarted(QWebEngineUrlRequestJob *request) override
          {
              QByteArray request_method = request->requestMethod();
              if(request_method != "GET")
              {
                  request->fail(QWebEngineUrlRequestJob::RequestDenied);
                  return;
              }
      
              QUrl request_url = request->requestUrl();
              QString request_path = request_url.path();
              //qDebug()<<request_url<<endl;
      
              QString application_path = "D:/";
              QFile *file = new QFile(application_path + request_path);
              file->setParent(request);
              connect(request, &QObject::destroyed, file, &QFile::deleteLater);
              //qDebug()<<file->size()<<endl;
              if(!file->exists()||file->size()==0)
              {
                  printf("resource '{request_path}' not found or is empty");
                  request->fail(QWebEngineUrlRequestJob::UrlNotFound);
                  return;
              }
      
              QFileInfo file_info = QFileInfo(*file);
              QMimeDatabase mime_database;
              QMimeType mime_type = mime_database.mimeTypeForFile(file_info);
              request->reply(QUrl(mime_type.name()).toEncoded(), file);
          }
      };
      
      int main(int argc, char *argv[])
      {
          char ARG_DISABLE_WEB_SECURITY[] = "--disable-web-security";
          int newArgc = argc+1+1;
          char** newArgv = new char*[newArgc];
          for(int i=0; i<argc; i++) {
              newArgv[i] = argv[i];
          }
          newArgv[argc] = ARG_DISABLE_WEB_SECURITY;
          newArgv[argc+1] = nullptr;
      
          qputenv("QTWEBENGINE_REMOTE_DEBUGGING", "7542");    //用于调试
      
          QWebEngineUrlScheme scheme = QWebEngineUrlScheme("qt");
          scheme.setFlags(QWebEngineUrlScheme::CorsEnabled);
          QWebEngineUrlScheme::registerScheme(scheme);
      
          //QApplication a(argc, argv);
          QApplication a(newArgc, newArgv);
      
          QWebEngineView view;
      
          QtSchemeHandler *scheme_handler = new QtSchemeHandler();
          view.page()->profile()->installUrlSchemeHandler("qt", scheme_handler);
      
          view.page()->profile()->clearHttpCache();       //删除缓存
      
          //view.load(QUrl("D:/cesium/CesiumWork/3DTilesPhotogrammetry/3DTilesPhotogrammetry.html"));
          view.load(QUrl("qt://local/cesium/CesiumWork/3DTilesPhotogrammetry/3DTilesPhotogrammetry.html"));
      
          view.show();
      
          return a.exec();
      }
      

      这个方案的本质是将URL定义地址的资源给转发了一遍。但是这种方案还是有局限性,经过测试,在Qt5.15.2版本中可行,但在Qt5.12.5版本中不行。而且这样所有的资源地址都得采用这一套URL方案。

      3. 建议

      其实个人还是不太建议再轻易尝试使用本地网页跨域了,毕竟这一点与Web的安全性背道而驰。最好还是让网页在服务器环境下吧,出问题的可能性会小一点。

      4. 参考

      • Qt QWebEngineView not allowed to load local resource
      • PyQt5 How To Use JavaScript Modules

       到此这篇关于Qt(QtWebEngine)加载本地网页跨域问题的总结的文章就介绍到这了,更多相关Qt(QtWebEngine)加载本地网页跨域问题的总结内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

      声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。