第8章 ZooKeeper操作

来源:https://www.cnblogs.com/dreamboy/archive/2018/07/10/9289883.html
-Advertisement-
Play Games

[TOC] 8.1 集群環境搭建 【操作目的】 由於在ZooKeeper集群中,會有一個Leader伺服器負責管理和協調其他集群伺服器,因此伺服器的數量通常都是單數,例如3,5,7...等,這樣數量為2n+1的伺服器就可以允許最多n台伺服器的失效。 【操作步驟】 本例中,我們仍然使用三個節點搭建部署 ...


目錄

8.1 集群環境搭建

【操作目的】
由於在ZooKeeper集群中,會有一個Leader伺服器負責管理和協調其他集群伺服器,因此伺服器的數量通常都是單數,例如3,5,7...等,這樣數量為2n+1的伺服器就可以允許最多n台伺服器的失效。
【操作步驟】
本例中,我們仍然使用三個節點搭建部署ZooKeeper集群,搭建步驟如下:

1.上傳ZooKeeper安裝文件

在centos01節點中,上傳ZooKeeper安裝文件zookeeper-3.4.9.tar.gz到目錄/opt/softwares/中,並將其解壓到目錄/opt/modules/,解壓命令如下:

tar -zxvf zookeeper-3.4.9.tar.gz -C /opt/modules/

2.編寫配置文件

(1)在ZooKeeper安裝目錄下新建文件夾dataDir,用於存放ZooKeeper數據。
(2)在ZooKeeper安裝目錄下的conf文件夾中新建配置文件zoo.cfg,加入以下內容:

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/opt/modules/zookeeper-3.4.9/dataDir
clientPort=2181

server.1=centos01:2888:3888
server.2=centos02:2888:3888
server.3=centos03:2888:3888

上述參數說明如下:
initLimit:集群中的Follower伺服器初始化連接Leader伺服器時能等待的最大心跳數(連接超時時長)。預設為10,即如果經過10個心跳之後Follower伺服器仍然沒有收到Leader伺服器的返回信息,則連接失敗。本例中該參數值為5,參數tickTime為2000,則連接超時時長為52000=10秒(即tickTimeinitLimit=10秒)。
syncLimit:集群中的Follower伺服器與Leader伺服器之間發送消息以及請求/應答時所能等待的最多心跳數。本例中,tickTime的值為2,時長為2*2000=4秒。
server.id:標識不同的ZooKeeper伺服器。ZooKeeper可以從“server.id=host:port1:port2”中讀取相關信息。其中,id值必須在整個集群中是唯一的,且大小在1到255之間;host是伺服器的名稱或IP地址;第一個埠(port1)是Leader埠,即該伺服器作為Leader時供Follower連接的埠;第二個埠(port2)是選舉埠,即選舉Leader伺服器時供其它Follower連接的埠。
dataDir:ZooKeeper保存數據的目錄。
clientPort:客戶端連接ZooKeeper伺服器的埠,ZooKeeper會監聽這個埠,接收客戶端的請求。
(3)在配置文件zoo.cfg中的參數dataDir指定的目錄下(此處為ZooKeeper安裝目錄下的dataDir文件夾)新建一個名為myid的文件,這個文件僅包含一行內容,即當前伺服器的id值,與參數server.id中的id值相同。本例中,當前伺服器(centos01)的id值為1,則應該在myid文件中寫入數字1。ZooKeeper啟動時會讀取該文件,將其中的數據與zoo.cfg里寫入的配置信息進行對比,從而獲取當前伺服器的身份信息。

3.拷貝ZooKeeper安裝信息到其它節點

centos01節點安裝完成後,需要拷貝整個ZooKeeper安裝目錄到centos02和centos03節點,命令如下:

scp -r /opt/modules/zookeeper-3.4.9/ hadoop@centos02:/opt/modules/
scp -r /opt/modules/zookeeper-3.4.9/ hadoop@centos03:/opt/modules/

4.修改其它節點配置

拷貝完成後,需要將centos02和centos03節點中的myid文件的值修改為對應的數字,即作出以下操作:
修改centos02節點中的opt/modules/zookeeper-3.4.9/dataDir/myid文件中的值為2。
修改centos03節點中的opt/modules/zookeeper-3.4.9/dataDir/myid文件中的值為3。

5.啟動ZooKeeper

分別進入每個節點的ZooKeeper安裝目錄,執行如下命令:

bin/zkServer.sh start

輸出以下信息代表啟動成功:
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper-3.4.9/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED

需要註意的是,每台伺服器都要執行一遍啟動命令,這樣才能使得整個集群啟動起來。

6.查看啟動狀態

分別在各個節點上執行如下命令,查看ZooKeeper服務的狀態:

bin/zkServer.sh status

在centos01節點上查看服務狀態,輸出了以下信息:
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper-3.4.9/bin/../conf/zoo.cfg
Mode: follower

在centos02伺服器上查看服務狀態,輸出了以下信息:
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper-3.4.9/bin/../conf/zoo.cfg
Mode: follower

在centos03伺服器上查看服務狀態,輸出了以下信息:
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper-3.4.9/bin/../conf/zoo.cfg
Mode: leader

由此可見,本例中centos03伺服器上的ZooKeeper服務為Leader,其餘兩個ZooKeeper服務為Follower。
如果在查看啟動狀態時輸出以下信息,說明ZooKeeper集群啟動不成功,出現錯誤。
Error contacting service. It is probably not running.
此時需要修改bin/zkEvn.sh文件中的以下內容,將錯誤信息輸出到日誌文件。

if [ "x${ZOO_LOG4J_PROP}" = "x" ]  
then  
    ZOO_LOG4J_PROP="INFO,CONSOLE"  
fi  

將上述內容中的CONSOLE改為ROLLINGFILE,修改後的內容如下:

if [ "x${ZOO_LOG4J_PROP}" = "x" ]  
then  
    ZOO_LOG4J_PROP="INFO,ROLLINGFILE"  
fi  

修改後,重新啟動ZooKeeper集群,查看在ZooKeeper安裝目錄下生成的日誌文件zookeeper.log,發現報以下錯誤:
java.net.NoRouteToHostException: 沒有到主機的路由。
產生上述錯誤的原因是,系統沒有關閉防火牆,導致ZooKeeper集群間連接不成功。因此需要關閉系統防火牆(為了防止出錯,在最初的集群環境配置的時候可以直接將防火牆關閉),CentOS7關閉防火牆的命令如下:

systemctl stop firewalld.service
systemctl disable firewalld.service

關閉各節點的防火牆後,重新啟動ZooKeeper,再一次查看啟動狀態,發現一切正常了。

7.測試客戶端連接

在centos01節點上(其它節點也可以),進入ZooKeeper安裝目錄,執行以下命令,可以連接ZooKeeper伺服器,連接成功後可以輸入ZooKeeper的Shell命令進行操作與測試了。

[hadoop@centos01]$ bin/zkCli.sh -server centos01:2181

8.2 命令行操作

【操作目的】
ZooKeeper的命令行工具類似於Shell。當ZooKeeper服務啟動以後,可以在其中一臺運行ZooKeeper服務的伺服器中輸入以下命令(需要進入ZooKeeper安裝目錄),啟動一個客戶端,連接到ZooKeeper集群:
[hadoop@centos01]$ bin/zkCli.sh -server centos01:2181
連接成功後,系統會輸出ZooKeeper的運行環境及配置信息,併在屏幕輸出“Welcome to ZooKeeper”等歡迎信息。之後就可以使用ZooKeeper命令行工具了。
【操作步驟】
以下是ZooKeeper命令行工具的一些簡單操作示例:
(1)使用ls命令,可以查看當前ZooKeeper中所包含的內容:

[zk: centos01:2181(CONNECTED) 4] ls /
[zookeeper]

可以看到,當前有一個名稱為zookeeper的Znode節點。
(2)使用create命令,可以創建一個新的Znode節點。例如,創建一個名為“zk”的Znode以及在它上面存放的元數據字元串“myData”,命令及輸出信息如下:

[zk: centos01:2181(CONNECTED) 2] create /zk "myData"
Created /zk 

(3)使用get命令,可以查看某個Znode的詳細信息及其包含的元數據字元串。例如,查看Znode節點/zk的詳細信息,命令及輸出信息如下:

[zk: centos01:2181(CONNECTED) 6] get /zk
myData
cZxid = 0x800000002
ctime = Thu Mar 22 10:12:11 CST 2018
mZxid = 0x800000002
mtime = Thu Mar 22 10:12:11 CST 2018
pZxid = 0x800000002
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 6
numChildren = 0

(4)使用set命令,可以修改Znode節點的元數據字元串。例如,將Znode節點/zk所關聯的字元串修改為“myDataUpdate”,命令及輸出信息如下:

[zk: centos01:2181(CONNECTED) 10] set /zk "myDataUpdate"
cZxid = 0x800000002
ctime = Thu Mar 22 10:12:11 CST 2018
mZxid = 0x800000005
mtime = Thu Mar 22 10:18:19 CST 2018
pZxid = 0x800000002
cversion = 0
dataVersion = 3
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 12
numChildren = 0

(5)使用delete命令,可以將某個Znode節點刪除。例如,刪除上面創建的Znode節點/zk,命令如下:

[zk: centos01:2181(CONNECTED) 11] delete /zk

使用ZooKeeper命令行工具也可以創建有層次的目錄。例如,在/zk節點目錄下創建新的目錄node1,並關聯其元數據為“nodeData”,命令及輸出信息如下:

[zk: centos01:2181(CONNECTED) 18] create /zk/node1 "nodeData"
Created /zk/node1

8.3 Java API操作

除了可以使用命令行方式對ZooKeeper進行操作外,ZooKeeper還提供了Java API操作介面。下麵對ZooKeeper的常用Java API介面進行介紹。

8.3.1 創建Java工程

在編寫Java API之前,首先需要新建一個ZooKeeper項目。ZooKeeper項目的結構與普通的Java項目一樣,只是依賴的jar包不同。
在eclipse中新建一個Maven項目zk_demo(Maven項目的搭建此處不做過多講解),然後在該項目的pom.xml文件中添加以下代碼,以引入ZooKeeper的Java API依賴包:

   <dependency>
     <groupId>org.apache.zookeeper</groupId>
     <artifactId>zookeeper</artifactId>
     <version>3.4.9</version>
   </dependency>

配置好pom.xml後,即可進行ZooKeeper Java API的編寫。

8.3.2 創建節點

Zookeeper創建節點不支持遞歸調用,即無法在父節點不存在的情況下創建一個子節點,如在/zk0l節點不存在的情況下創建/zk01/ch01節點;並且如果一個節點已經存在,那麼創建同名節點時,會拋出NodeExistsException異常。
下麵我們創建一個節點/ zk001,節點的元數據為“zk001_data”,步驟如下:

1.編寫代碼

在新建的zk_demo項目中新建Java類CreatePath.java,完整代碼如下所示:

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.ZooDefs.Ids;

public class CreatePath {

    public static void main(String[] args) throws Exception {
        String connectStr="192.168.170.128:2181,192.168.170.129:2181,192.168.170.130:2181";
        //參數1:伺服器連接字元串
        //參數2:連接超時時間
        //參數3:觀察者對象(回調函數)
        ZooKeeper zk = new ZooKeeper(connectStr, 3000, null);       
        /* 1.CreateMode 取值   
         *  PERSISTENT:持久化節點
         *  PERSISTENT_SEQUENTIAL:順序自動編號的目錄節點
         *  EPHEMERAL:臨時目錄節點,客戶端斷開連接時,這種節點會被自動刪除 
         *  EPHEMERAL_SEQUENTIAL:臨時自動編號節點 
         *  */
        String path=zk.create("/zk001", "zk001_data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        System.out.println(path);
    }
}

2.程式解讀

ZooKeeper zk  = new ZooKeeper(connectStr, 3000, null);

新建一個ZooKeeper對象,傳入三個參數,第一個參數為以逗號分隔的伺服器連接字元串,格式:“host:埠”,這裡需要把所有的ZooKeeper伺服器的地址都寫上,而不是只寫其中一臺。ZooKeeper客戶端對象將從連接串中挑選任意一個伺服器進行連接,如果連接失敗,將嘗試連接另外一個伺服器,直到建立連接。這樣的好處是能保證ZooKeeper服務的高可靠性,防止因為其中一臺機器宕機而導致連接失敗。第二個參數為連接超時時間,這裡是3秒。第三個參數為觀察者對象,連接成功後會調用觀察者對象中的回調函數,這裡傳入null即可。

String path=zk.create("/zk001", "zk001_data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

調用ZooKeeper對象的創建節點函數,返回創建的節點路徑,並需要傳入四個參數。第一個參數為節點名稱。第二個參數為節點數據,需要轉成位元組數組。第三個參數為許可權控制,這裡使用ZooKeeper自帶的完全開放許可權Ids.OPEN_ACL_UNSAFE。第四個參數為創建模式,它是一個枚舉類型,共有四個取值,PERSISTENT(持久化,這個目錄節點存儲的數據不會丟失 ,即客戶端失去連接之後不會被自動刪除)、PERSISTENT_SEQUENTIAL(順序自動編號的目錄節點,這種目錄節點在命名上會根據當前已經存在的節點數自動加 1,然後將已經成功創建的目錄節點名返回給客戶端)、EPHEMERAL(臨時目錄節點,客戶端斷開連接時,這種節點會被自動刪除)、EPHEMERAL_SEQUENTIAL(臨時自動編號目錄節點,客戶端斷開連接時,這種節點也會被自動刪除)。

3.運行程式

直接在eclipse中右擊運行該程式即可。

8.3.3 添加數據

我們可以通過調用ZooKeeper對象的setData()函數給節點添加數據,示例代碼如下:

@Test  
    public void setNodeData() throws Exception {  
        String connectStr="192.168.170.128:2181,192.168.170.129:2181,192.168.170.130:2181";
        ZooKeeper zk  = new ZooKeeper(connectStr, 3000, null);  
        Stat stat = zk.setData("/zk002", "zk002_data2".getBytes(), -1);  
        System.out.println(stat.getVersion());
    }

代碼解析:

Stat stat = zk.setData("/zk002", "zk002_data2".getBytes(), -1);

setData函數的第一個參數為節點路徑。第二個參數為需要添加的數據,並轉成位元組數組。第三個參數為版本號,-1代表所有版本。

8.3.4 獲取數據

我們可以調用ZooKeeper對象的getData()函數,獲得指定節點的數據,示例代碼如下:

@Test  
    public void getNodeData() throws Exception {  
        String connectStr="192.168.170.128:2181,192.168.170.129:2181,192.168.170.130:2181";
        ZooKeeper zk  = new ZooKeeper(connectStr, 3000, null);  
        Stat stat=new Stat();
    //返回指定路徑上的節點數據和節點狀態,節點的狀態會放入stat對象中
    byte[] bytes=zk.getData("/zk002", null, stat);
    System.out.println(new String(bytes));
    }

上述代碼獲取了節點/zk002的數據,而且轉成了字元串進行了輸出,並將節點/zk002的狀態放入了對象stat中。如需查看狀態信息,可以從對象stat中進行輸出查看。
可以看到,在getData函數的第二個參數,傳入的是null,也可以指定一個觀察者對象watcher,對節點數據的變化進行監聽,一旦有數據改變,就會觸發watcher指定的回調函數。我們對上方代碼加入觀察者後,示例代碼如下:

@Test  
    public void getNodeDataWatch() throws Exception {  
        String connectStr="192.168.170.128:2181,192.168.170.129:2181,192.168.170.130:2181";
        ZooKeeper zk  = new ZooKeeper(connectStr, 3000, null);  
        Stat stat=new Stat();
        //返回指定路徑上的節點數據和節點狀態,節點的狀態會放入stat對象中
        byte[] bytes=zk.getData("/zk002", new Watcher(){
            @Override
            public void process(WatchedEvent event) {
                System.out.println(event.getType());
            }
            
        }, stat);
        System.out.println(new String(bytes));
        
        //改變節點數據,觸發watch
        zk.setData("/zk002", "zk002_data_testwatch".getBytes(), -1); 
        
        //為了驗證是否觸發了watch,不讓程式結束
        while(true){
            Thread.sleep(3000);
        }
        
    }

代碼分析:

public void process(WatchedEvent event) {
    System.out.println(event.getType());
}

process 方法是 Watcher 介面中的一個回調方法,當 ZooKeeper 向客戶端發送一個 Watcher 事件通知時,客戶端就會對相應的 process 方法進行回調,從而實現對事件的處理。
process 方法包含 WatcherEvent 類型的參數,WatchedEvent 包含了每一個事件的三個基本屬性:通知狀態(KeeperState)、事件類型(EventType)和節點路徑(Path),ZooKeeper 使用 WatchedEvent 對象來封裝服務端事件並傳遞給 Watcher,從而方便回調方法 process 對服務端事件進行處理。
上述代碼通過System.out.println(event.getType());輸出服務端的事件類型,輸出結果為NodeDataChanged。從結果單詞的含義可知,節點數據被改變了。

while(true){
    Thread.sleep(3000);
}

為了能夠更好的驗證是否觸發了watch,不讓程式一次執行到底,從而加入了上方代碼,讓程式一直停留在此處。

8.3.5 刪除節點

我們可以通過調用ZooKeeper對象的delete()函數,對指定路徑節點進行刪除。示例代碼如下:

@Test
    public void deletePath() throws Exception{
        String connectStr="192.168.170.128:2181,192.168.170.129:2181,192.168.170.130:2181";
        ZooKeeper zk  = new ZooKeeper(connectStr, 3000, null);  
        //刪除節點 
        zk.delete("/zk001", -1);
    }

上述代碼中,delete函數需要傳入兩個參數,第一個參數為需要刪除的節點路徑。第二個參數為節點版本,如果是-1則代表刪除所有版本。

原創文章,轉載請註明出處!!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.終端執行 /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 2.執行命令後出現兩個錯,並附如何解決 備註:博主本人macos是在虛擬機上跑的,尚未有 ...
  • 生產環境使用 Fedora 28, 並且需要搭建一個 Jupyter 的notebook 方便使用,所搭建的Jupyter 支持單人遠程 密碼訪問 1. 安裝 安裝 Jupyter , 出錯 安裝 redhat-rpm-config 安裝 python-devel 安裝 notebook 2. 運行 ...
  • 第13章 RTX操作系統版本二代示波器實現 本章教程為大家講解RTX操作系統版本的二代示波器實現。主要講解RTOS設計框架,即各個任務實現的功能,任務間的通信方案選擇,任務棧,系統棧以及全局變數共用問題。同時,工程調試方法也專門做了說明。 13.1 註意事項(重要必讀) 13.2 任務功能劃分 13 ...
  • 第1章 什麼是運維 1.1 運維的職責: 1、 數據不能丟 2、 網站7*24小時 3、 用戶體驗要好 要求伺服器穩定性比普通家用機高 1.2 運維人員的原則: 簡單,易用,高效 (簡單,粗暴) 第2章 伺服器的組成詳解 2.1 伺服器 2.1.1 伺服器的類型: 機架式伺服器、刀片式伺服器、塔式服 ...
  • 1、利用netstat查看 TIME_WAIT 情況 2、利用netstat查看是哪個ip遠程訪問了伺服器 3、利用netstat查看指定的網路程式占用了哪個網路埠 ...
  • 游標 游標是sql的一個記憶體工作區,由系統或用戶以變數的形式定義,用於臨時存儲從資料庫中提取的數據塊。 游標分為顯式游標和隱式游標,可自定義顯式游標用來存儲多行多列的數據。 顯式游標一旦打開,就相當於執行了select語句,執行的結果集就存儲在游標中。 隱式游標 在進行DML操作和單行SELECT語 ...
  • 這篇博文里的好多內容之前在讀《大數據時代》時讀到過,所以就算是補上的讀書筆記? 信息科技為大數據時代提供技術支撐 1.存儲設備容量不斷增加 2.CPU處理能力大幅提升 3.網路帶寬不斷增加 數據產生方式的變革促成大數據時代的來臨 1.運營式系統階段 2.用戶原創內容階段 3.感知式系統階段 大數據的 ...
  • 一. 概述 存儲過程和函數是事先經過編譯並存儲在資料庫中的一段sql語句集合,可以簡化應用開發人員的很多工作,減少數據在資料庫與應用伺服器之間的傳輸,提高數據處理效率是有好處的。存儲過程和函數的區別在於函數必須有返回值,存儲過程的參數可以使用in,out ,inout類型,而函數參數只能是in類型。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...