Qt+QtWebApp開發筆記(五):http伺服器html中使用json觸發ajax與後臺互動實現資料更新傳遞

2023-06-09 12:00:27

前言

  前面完成了頁面的跳轉、登入,很多時候不重新整理頁面就想重新整理區域性資料,此時ajax就是此種技術,且是非同步的。
  本篇實現網頁內部使用js呼叫ajax實現非同步互動資料。
  在js中使用 ajax是通過XMLHttpRequest來實現的。

 

Demo

  在這裡插入圖片描述

下載地址

 

Ajax與XMLHttpRequest

Ajax

  Ajax即Asynchronous Javascript And XML(非同步JavaScript和XML)在 2005年被Jesse James Garrett提出的新術語,用來描述一種使用現有技術集合的‘新’方法,包括:HTML或XHTML、CSS、JavaScript、DOM、XML、XSLT以及最重要的XMLHttpRequest。使用Ajax技術網頁應用能夠快速地將增量更新呈現在使用者介面上,而不需要過載(重新整理)整個頁面,這使得程式能夠更快地迴應使用者的操作。
  Ajax不是一種新的程式語言,而是一種用於建立更好更快以及互動性更強的Web應用程式的技術。使用JavaScript向伺服器提出請求並處理響應而不阻塞使用者核心物件XMLHttpRequest。通過這個物件,JavaScript可在不過載頁面的情況與Web伺服器交換資料,即在不需要重新整理頁面的情況下,就可以產生區域性重新整理的效果。Ajax在瀏覽器與 Web 伺服器之間使用非同步資料傳輸(HTTP 請求),這樣就可使網頁從伺服器請求少量的資訊,而不是整個頁面。

  • Ajax可使因特網應用程式更小、更快,更友好。
  • Ajax是一種獨立於Web伺服器軟體的瀏覽器技術。
  • Ajax基於Web標準:JavaScript、XML、HTML與CSS,在Ajax中使用的Web標準已被良好定義,並被所有的主流瀏覽器支援。
  • Ajax用程式獨立於瀏覽器和平臺。

  Web應用程式較桌面應用程式有諸多優勢;它們能夠涉及廣大的使用者,它們更易安裝及維護,也更易開發。但是,因特網應用程式並不像傳統的桌面應用程式那樣完善且友好。 通過 Ajax,因特網應用程式可以變得更完善,更友好。

 

XMLHttpRequest

  XMLHTTP是一組API函數集,可被JavaScript、JScript、VBScript以及其它web瀏覽器內嵌的指令碼語言呼叫,通過HTTP在瀏覽器和web伺服器之間收發XML或其它資料。XMLHTTP最大的好處在於可以動態地更新網頁,它無需重新從伺服器讀取整個網頁,也不需要安裝額外的外掛。該技術被許多網站使用,以實現快速響應的動態網頁應用。例如:Google的Gmail服務、Google Suggest動態查詢介面以及Google Map地理資訊服務。
  XMLHTTP是AJAX網頁開發技術的重要組成部分。除XML之外,XMLHTTP還能用於獲取其它格式的資料,如JSON或者甚至純文字。
  使用XMLHttpRequest來傳送HTTP請求以實現網站和伺服器之間的資料交換。
  XMLHttpRequest物件是Ajax的核心,它有許多的屬性、方法和事件。

屬性

readyState:當前狀態

  當一個XMLHttpRequest物件被建立後,readyState屬性標識了當前物件的狀態。
  在這裡插入圖片描述

responseText:響應文字

responseText屬性包含使用者端接收到的HTTP響應的文字內容。

  • readyState為0、1、2時:為一個空字串;
  • readyState為3時:為還未完成的響應資訊;
  • readyState為4時:為含完整的響應資訊;

statusText:狀態文字

  描述了HTTP狀態程式碼文字,並且僅當readyState屬性值為3或4時才可用。檢測返回結果的判斷就是:

if(readyState===4 && statusText===200)
{
	……
}

  如我們的Demo:
  在這裡插入圖片描述

函數

open():初始化請求

open(method, url, async, username, password)
  • 引數method:請求的型別,GET、POST、PUT、DELETE、HEAD型別,輸入的時候使用大寫;
  • 引數url:請求的資源地址,請求資源的web api地址;
  • 引數async:是否傳送非同步請求,true-非同步請求,false-同步請求;
  • 引數username(可為空):需要伺服器驗證存取使用者時,設定username;
  • 引數password(可為空):需要伺服器驗證存取使用者時,設定password;

send():傳送請求

  呼叫open()方法後,再呼叫send()方法將請求傳送。當open()方法中async引數為true(非同步)時,在send()方法呼叫後立即返回,否則將會中斷直到請求返回。

setRequestHeader():設定頭部資訊

  設定請求的頭部資訊

getResponseHeader():獲取頭部資訊

  獲取請求的頭部資訊

事件

  onreadystatechange:狀態變化事件
  當readyState屬性值發生改變時,就會觸發onreadystatechang事件,程式碼中是依賴onreadystatechang進一步判斷狀態和狀態文字來做處理。
  在這裡插入圖片描述

 

使用XMLHttpRequest的步驟

步驟一:在指令碼中範例化XHMLHttpRequest

var xhr = new XMLHttpRequest();

步驟二:初始化請求open()

xhr.open('GET','/checkState/data',true);

步驟三:傳送請求

xhr.send();

步驟四:書寫事件處理常式並判斷狀態和狀態文字

xhr.onreadystatechange = function() {
	if(xhr.readyState === 4 && xhr.status === 200)
	{
		……
	}
}

步驟五:書寫返回成功的js處理程式碼

document.getElementById("dt2").innerHTML = xhr.responseText;
 

Demo增量使用ajax互動過程

步驟一:準備程式碼模板

  準備之前的demo v1.3.0模板:
  在這裡插入圖片描述

步驟二:新增checkState.html頁面

  下面是新增定時獲取和手動按鈕獲取得html:
  在這裡插入圖片描述

步驟三:建立CheckStateRequestHandle處理

  新建了一個處理,特別是增加了對於ajax技術的路徑處理
  在這裡插入圖片描述

  在這裡插入圖片描述

步驟四:將CheckStateRequestHandle接入

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

 

Demo原始碼

checkState.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><a>這裡是檢測狀態Demo v1.4.0了</a></p>
	<p><a id="dt1">123.567</a></p>
	<p><a id="dt2">123.567</a></p>
	<p><a id="dt3">123.567</a></p>
	<p><button onclick="reset()">清空</button></p>
	<p><button onclick="getDt1()">獲取</button></p>
	<script>
		function reset() {
			document.getElementById("dt1").innerHTML="---.---";
			document.getElementById("dt2").innerHTML="---.---";
			document.getElementById("dt3").innerHTML="---.---";
		}
		function getDt1() {
			var xhr = new XMLHttpRequest();
			xhr.open('GET','/checkState/data',true);
			xhr.send();
			xhr.onreadystatechange = function() {
				if(xhr.readyState === 4 && xhr.status === 200)
				{
					document.getElementById("dt1").innerHTML = xhr.responseText;
				}
			}
			
		}
	</script>
	<script>
		/* 定時獲取dt2 */
		function getDt2() {
			var xhr = new XMLHttpRequest();
			xhr.open('GET','/checkState/data',true);
			xhr.send();
			xhr.onreadystatechange = function() {
				if(xhr.readyState === 4 && xhr.status === 200)
				{
					document.getElementById("dt2").innerHTML = xhr.responseText;
				}
			}
		}
		window.setInterval(getDt2, 1000);
	</script>
</body>

CheckStateRequestHandler.h

#ifndef CHECKSTATEREQUESTHANDLER_H
#define CHECKSTATEREQUESTHANDLER_H

#include "httprequesthandler.h"

using namespace stefanfrings;

class CheckStateRequestHandler : public HttpRequestHandler
{
public:
    CheckStateRequestHandler(QObject *parent = 0);

public:
    void service(HttpRequest& request, HttpResponse& response);

private:
    QTextCodec *_pTextCodec;
};

#endif // CHECKSTATEREQUESTHANDLER_H

CheckStateRequestHandler.cpp

#include "CheckStateRequestHandler.h"

#include "DataManager.h"

#include <QTextCodec>
#include <QApplication>

#include <QDebug>
#include <QDateTime>
//#define LOG qDebug()<<__FILE__<<__LINE__
//#define LOG qDebug()<<__FILE__<<__LINE__<<__FUNCTION__
//#define LOG qDebug()<<__FILE__<<__LINE__<<QThread()::currentThread()
//#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd")
#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz")

using namespace stefanfrings;

CheckStateRequestHandler::CheckStateRequestHandler(QObject *parent)
    : HttpRequestHandler(parent)
{
    // 返回文字(我們需要在瀏覽器上看,所以將Qt內部編碼都轉成GBK輸出即可,不管他本身是哪個編碼)
    // WINDOWS: GBK  GB2312
    // LINUX  : urf-8
//    _pTextCodec = QTextCodec::codecForName("utf-8");
    _pTextCodec = QTextCodec::codecForName("GBK");
}

void CheckStateRequestHandler::service(HttpRequest &request, HttpResponse &response)
{
    QString str;

    QString path = request.getPath();
    LOG << path;


    if(path == "/checkState")
    {
        // 為了方便,開始單獨載入html檔案做處理
        QString filePath = QString("%1/html/checkState.html").arg(qApp->applicationDirPath());
        QFile file(filePath);
        if(!file.open(QIODevice::ReadOnly))
        {
            str = QString("The URL is wrong, no checkState.html [%1]").arg(filePath);
        }else{
            str = file.readAll();
            file.close();
        }
    }else if(path == "/checkState/data")
    {
        str = DataManager::getInstance()->getDt1Value();
    }else {
        response.setStatus(404,"Not found");
        str = "The URL is wrong, no such document.";
    }

    // 返回文字(我們需要在瀏覽器上看,所以將Qt內部編碼都轉成GBK輸出即可,不管他本身是哪個編碼)
//    QByteArray byteArray = _pTextCodec->fromUnicode(str);
    QByteArray byteArray = str.toUtf8();
    response.write(byteArray);
}
 

工程模板v1.4.0

  在這裡插入圖片描述