Qt中QtWebEngine加載本地網(wǎng)頁跨域問題的總結(jié)
1. 概述
瀏覽器直接加載本地網(wǎng)頁的時候,如果網(wǎng)頁涉及到加載本地資源(如圖片),會出現(xiàn)跨域的問題。Qt的Qt WebEngine模塊基于Chromium項目,遇到這樣的情況也會出現(xiàn)跨域的問題。
2. 詳論
2.1. 傳參
理論上,我們可以像設(shè)置chrome瀏覽器跨域一樣(設(shè)置chrome瀏覽器跨域網(wǎng)上的資料非常多),給我們使用的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會將跨域參數(shù)傳遞到Qt WebEngine模塊的Chromium內(nèi)核中,從而實現(xiàn)跨域。
2.2. JS module
即使設(shè)置跨域,當使用JavaScript ES6 module的時候,仍然有可能會出現(xiàn)跨域的問題。
一個顯而易見的錯誤提示如下:
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卻可以)?,F(xiàn)在最新版本的Chrome的跨域設(shè)置已經(jīng)可以支持ES6 module,但是Qt WebEngine模塊卻可能是比較低的Chromium版本,從而造成使用ES6 module遇到跨域問題。通常來說,越新的Qt版本,Chromium版本也會越高。
如果還是不想要服務(wù)器環(huán)境,那么一種解決方案就是自定義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"); //用于調(diào)試 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(); }
這個方案的本質(zhì)是將URL定義地址的資源給轉(zhuǎn)發(fā)了一遍。但是這種方案還是有局限性,經(jīng)過測試,在Qt5.15.2版本中可行,但在Qt5.12.5版本中不行。而且這樣所有的資源地址都得采用這一套URL方案。
3. 建議
其實個人還是不太建議再輕易嘗試使用本地網(wǎng)頁跨域了,畢竟這一點與Web的安全性背道而馳。最好還是讓網(wǎng)頁在服務(wù)器環(huán)境下吧,出問題的可能性會小一點。
4. 參考
到此這篇關(guān)于Qt(QtWebEngine)加載本地網(wǎng)頁跨域問題的總結(jié)的文章就介紹到這了,更多相關(guān)Qt(QtWebEngine)加載本地網(wǎng)頁跨域問題的總結(jié)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言中字符和字符串處理(ANSI字符和Unicode字符)
這篇文章主要介紹了C語言與C++中字符和字符串處理(ANSI字符和Unicode字符)的詳細內(nèi)容,非常的全面,這里推薦給大家,希望大家能夠喜歡。2015-03-03C++靜態(tài)成員變量和靜態(tài)成員函數(shù)的使用方法總結(jié)
下面小編就為大家?guī)硪黄狢++靜態(tài)成員變量和靜態(tài)成員函數(shù)的使用方法總結(jié)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-01-01