Qt+QtWebApp開發筆記(六):http服務器html實現靜態相對路徑調用第三方js文件

前言

  前面做了一些交互,網頁是直接通過html對response進行返回的,這裏QtWebApp與傳統的web服務器不同,傳統的web服務器可以調用同級目錄相對路徑或者絕對路徑下的js,而QtWebApp的httpserver是response返回當前頁面的問題,默認是無法調用的。
  爲了解決調用一些依賴的如echarts等一些js的代碼模塊引入的問題,就需要靜態文件了。
本篇解說StaticFileController,在返回的html文本中調用外部js文件,類似的,其他文件都是一樣了,只是引入的後綴名不一樣。

 

Demo

  這裏是調用靜態文件js的
  在這裏插入圖片描述

  這裏是重定向測試的
  在這裏插入圖片描述

 

靜態文件(重要功能,如調用服務器的js文件等)

  如果QtWebapp無法傳遞存儲在服務器文件夾中的靜態文件,那麼它將是不完整的。StaticFileController提供了這一功能。但在使用它之前,需要在ini文件中進行一些額外的配置設置:

[files]
path=../docroot
encoding=UTF-8
maxAge=90000
cacheTime=60000
cacheSize=1000000
maxCachedFileSize=65536

  

  • path:設置指定存儲靜態文件的基本文件夾。它是相對於配置文件的。還可以編寫絕對路徑名,如“/opt/server/docroot”或“C:/server/docroot”。
  • encoding:encoding參數僅用於*.txt和*.html文件,用於告訴瀏覽器這些文件的編碼方式。如果同時需要不同的編碼,則必須創建StaticFileController的多個實例——每個編碼一個。
    其他參數控制高速緩存。首先,應該知道操作系統已經緩存了文件。然而,發現Linux和Windows在處理小文件時都表現不佳。因此,建議使用應用程序內部緩存,但僅適用於小文件。
  • cacheTime:cacheTime控制文件在內存中最多保存多少毫秒。值0表示,只要有足夠的空間,文件就會保留在內存中。
  • cacheSize:cacheSize指定允許緩存佔用的內存量。一兆字節是一個很好的開始值。如果用戶請求的文件不在緩存中,則會刪除最舊的文件,爲新文件騰出空間。
  • maxCachedFileSize:maxCachedFileSize控制緩存中單個文件的最大大小。web服務器應用程序不會緩存較大的文件。但正如所寫的那樣,操作系統可以很好地緩存大文件。事實證明,64千字節是一個很好的開始值。
  • maxAge:maxAge參數的含義與cacheTime基本相同,但控制網絡瀏覽器的緩存,而不是服務器。

  需要一個指向StaticFileController實例的全局指針,以便整個程序都可以訪問它。首先添加到
global.h:

#ifndef GLOBAL_H
#define GLOBAL_H

#include "httpsessionstore.h"
#include "staticfilefontroller.h"

using namespace stefanfrings;

extern HttpSessionStore* sessionStore;
extern StaticFileController* staticFileController;

#endif // GLOBAL_H

  global.cpp:

#include "global.h"

HttpSessionStore* sessionStore;
StaticFileController* staticFileController;

  在main.cpp中,配置StaticFileController的實例:

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    QString configFileName=searchConfigFile();

    // Session store
    QSettings* sessionSettings=new QSettings(configFileName,QSettings::IniFormat,&app);
    sessionSettings->beginGroup("sessions");
    sessionStore=new HttpSessionStore(sessionSettings,&app);

    // Static file controller
    QSettings* fileSettings=new QSettings(configFileName,QSettings::IniFormat,&app);
    fileSettings->beginGroup("files");
    staticFileController=new StaticFileController(fileSettings,&app);

    // HTTP server
    QSettings* listenerSettings=new QSettings(configFileName,QSettings::IniFormat,&app);
    listenerSettings->beginGroup("listener");
    new HttpListener(listenerSettings,new RequestMapper(&app),&app);

    return app.exec();
}

  現在可以在requestmapper.cpp中使用staticFileController:

#include "requestmapper.h"
#include "httpsession.h"
#include "global.h"

void RequestMapper::service(HttpRequest& request, HttpResponse& response) {
    QByteArray path=request.getPath();
    qDebug("RequestMapper: path=%s",path.data());

    if (path=="/" || path=="/hello") {
        helloWorldController.service(request, response);
    }
    else if (path=="/list") {
        listDataController.service(request, response);
    }
    else if (path=="/login") {
        loginController.service(request, response);
    }
    else if (path=="/cookie") {
        cookieTestController.service(request, response);
    }
    else if (path.startsWith("/files")) {
        staticFileController->service(request,response);
    }
    else {
        response.setStatus(404,"Not found");
        response.write("The URL is wrong, no such document.");
    }

    qDebug("RequestMapper: finished request");
}

  現在創建文件夾MyFirstWebApp/docroot/files,然後創建一個名爲hello.HTML的HTML文件:

<html>
    <body>
        Hello World!
    </body>
</html>

  啓動程序並打開http://localhost:8080/files/hello.html.瀏覽器將接收該文件的內容。
  可以將其他文件(圖像、css、javascript…)添加到該文件夾中,如果願意,還可以創建更多的子文件夾。
  如果出現“找不到文件”錯誤,調試消息將幫助找出服務器真正試圖加載的文件。

 

HTTP重定向

  有時想將瀏覽器重定向到另一個頁面。這通常用於需要用戶登錄的網站。如果用戶沒有登錄,他會被重定向到登錄頁面。當然,匿名用戶必須可以訪問登錄頁面本身。
  requestmapper.cpp中的更改:

void RequestMapper::service(HttpRequest& request, HttpResponse& response) {
    QByteArray path=request.getPath();
    qDebug("RequestMapper: path=%s",path.data());

    QByteArray sessionId=sessionStore->getSessionId(request,response);
    if (sessionId.isEmpty() && path!="/login") {
        qDebug("RequestMapper: redirect to login page");
        response.redirect("/login");
        return;
    }

    else if (path=="/login") {
        ...
    }

    else if (path=="/whatever") {
        ...
    }

    qDebug("RequestMapper: finished request");
}

國際化(ps:在文本中返回中文)

  HTTP服務器總是使用QByteArray而不是QString,原因很簡單:性能。整個HTTP協議都是基於8位編碼的,所以決定不浪費CPU時間,不必要地來回轉換。
但是當然可以使用Unicode。例子:

void UnicodeController::service(HttpRequest& request, HttpResponse& response) {
    QString chinese=QString::fromUtf8("美麗的花朵需要重症監護");
    response.setHeader("Content-Type", "text/html; charset=UTF-8");
    response.write(chinese.toUtf8(),true);
}

  這是谷歌翻譯(不會說中文)提供的“美麗的花朵需要重症監護”的中文翻譯。
  從QString到UTF-8的轉換並不比到Latin1的轉換慢。因此,如果需要,請隨時使用Unicode。但千萬不要忘記使用QString::fromUtf8。如果只寫中文=“美麗的花朵需要重症監護“,只會得到亂碼。

 

Demo增量:實戰配置加載靜態文件

步驟一:準備代碼模板

  準備之前的demo v1.4.0模板:

maxCachedFileSize=65536

步驟二:新增靜態文件管理類用於全局使用

  在這裏插入圖片描述
  在這裏插入圖片描述

步驟三:新增靜態配置

  新增靜態配置,路徑調整問exe當前的子目錄www(符合後端基本習慣)

[files]
path=../www
encoding=UTF-8
maxAge=90000
cacheTime=60000
cacheSize=1000000

步驟四:初始化靜態文件

  在這裏插入圖片描述
  在這裏插入圖片描述

步驟五:在Index進行路徑文件分流

  必須分流,靜態文件指示的api和文件是先從處理過程然後再到靜態文件管理類的,所以有些是請求數據則需要在代碼中處理,這裏之前是沒有這樣做,可查看“入坑一”。
  在這裏插入圖片描述

  本Demo無法打開跳轉的staticFileUserJs,可查看“入坑二”
  本Demo靜態文件無法調用js,請查看“入坑三”。

 

模塊化(有一些新增調整)

  在這裏插入圖片描述

 

Demo源碼

etc/httpServer.ini(新增files)

[listener]
;ip=127.0.0.1
port=8080
readTimeout=60000
maxRequestSize=16000
maxMultiPartSize=10000000
minThreads=4
maxThreads=100
cleanupInterval=60000

[logging]
fileName=../logs/httpserver.log
;fileName=/dev/stdout
minLevel=CRITICAL
bufferSize=100
maxSize=1000000
maxBackups=2
;timestampFormat=dd.MM.yyyy hh:mm:ss.zzz
timestampFormat=yyyy-MM-dd hh:mm:ss.zzz
msgFormat={timestamp} {typeNr} {type} {thread} {msg}
;QT5 supports: msgFormat={timestamp} {typeNr} {type} {thread} {msg}\n  in {file} line {line} function {function}

[files]
path=../www
encoding=UTF-8
maxAge=90000
cacheTime=60000
cacheSize=1000000
maxCachedFileSize=65536

www/index.html(新增文件,靜態文件主頁)

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>長沙紅胖子Qt</title>
</head>
<body>
	<p>你好, 長沙紅胖子 QQ:21497936 www.hpzwl.com</p>
	<p><a href="helloworld">Hello world!</a></p>
    <p><a href="list">list</a></p>
    <p><a href="login">login</a></p>
    <p><a href="checkState">checkState</a></p>
    <p><a href="staticFileUseJs.html">staticFileUseJs</a></p>
</body>

www/staticFileUseJs.html(新增文件,測試跳轉和js調用)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>長沙紅胖子Qt</title>
</head>
<body>
	<p><a>這裏是檢測狀態Demo v1.5.0了</a></p>
	<p><a id="dt1">123.567</a></p>
	<p><a id="dt2">123.567</a></p>	
	<p><button onclick="reset()">清空</button></p>
	<p><button onclick="getDt1()">獲取</button></p>
	<p><button onclick="doJs()">調用js</button></p>
	<script>
		function reset() {
			document.getElementById("dt1").innerHTML="---.---";
			document.getElementById("dt2").innerHTML="---.---";
			document.getElementById("dt3").innerHTML="---.---"
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章