Python讀取Ansible playbooks返回信息

来源:https://www.cnblogs.com/xuliuzai/archive/2023/11/26/17850437.html
-Advertisement-
Play Games

在今天的課上,我們深入討論了封裝、反射和單例模式這幾個重要的概念。我不想過多地贅述它們的細節,但是請大家務必記住它們的基本語法規則,因為這也是面向對象章節的結束。我希望大家能夠牢牢掌握這些知識點,為未來的學習打下堅實的基礎。 ...


一.背景及概要設計

當公司管理維護的伺服器到達一定規模後,就必然藉助遠程自動化運維工具,而ansible是其中備選之一。Ansible基於Python開發,集合了眾多運維工具(puppet、chef、func、fabric)的優點,實現了批量系統配置、批量程式部署、批量運行命令等功能。Ansible是藉助ssh來和遠程主機通訊的,不需要在遠程主機上安裝client/agents。因為上手容易,配置簡單、功能強大、擴展性強,在生產應用中得到了廣泛的應用。使用過程中,讀取、解析、判斷、保存Ansible playbooks 的執行返回信息是重要一壞。本文詳細描述如何實現Python讀取Ansible playbooks 執行返回信息,並且保存到資料庫中。

Ansible playbooks 的返回信息,有相應的格式。

例如:

PLAY [play to setup web server] *****************************************************

TASK [Gathering Facts] **************************************************************
ok: [172.177.117.129]
ok: [172.177.117.130]

TASK [Installed the latest httpd version] ***********************************************
ok: [172.177.117.129]
ok: [172.177.117.130]

TASK [restart service] ***********************************************************
changed: [172.177.117.129]
changed: [172.177.117.130]

PLAY RECAP **************************************************************************
172.177.117.129 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
172.177.117.130 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

從上面的例子可以看出,返回的運行信息還是很豐富的,從中可以得出play、task的名字、每個task執行情況,以及play運行情況的概況。

即:

 When you run a playbook, Ansible returns information about connections, the name lines of all your plays and tasks, whether each task has succeeded or failed on each machine, and whether each task has made a change on each machine. At the bottom of the playbook execution, Ansible provides a summary of the nodes that were targeted and how they performed. General failures and fatal “unreachable” communication attempts are kept separate in the counts.

重點及難點:從結果中找出規律,格式化結果,怎麼用正則表達式取得想要的信息。

二.表設計

通過對Ansible playbooks返回信息的分析,可以將其分成兩類(或者說兩部分),一是play的整體執行情況(主要信息為PLAY RECAP ),另一個是每個task的執行詳情。因此,我們設計了兩張表。

2.1 設計用來保存【最終執行結果】的表

ansible_play_recap

欄位名字 欄位類型 預設值 COMMENT
id bigint(20)  NOT NULL AUTO_INCREMENT 主鍵
manager_ip varchar(100)  NOT NULL 管理節點
clustername varchar(200)  NOT NULL 集群名字
playname varchar(360) NOT NULL Ansible劇本名稱
playrecap_serverip varchar(50) NOT NULL Ansible運行節點(受管節點)
playrecap_ok_qty varchar(10) NOT NULL 成功運行的task個數
playrecap_changed_qty varchar(10) NOT NULL 產生效果的task個數
playrecap_unreachable varchar(10) NOT NULL 相應的遠程節點是否不可達
playrecap_failed_qty varchar(10) NOT NULL 執行失敗的task個數【註意,不可達的情況,即未執行的情況下,失敗的個數記為0,此時是為執行的】
playrecap_skipped_qty varchar(10) NOT NULL 跳過的task的個數
playrecap_rescued_qty varchar(10) NOT NULL 搶救的task的個數
playrecap_ignored_qty varchar(10) NOT NULL 忽略的task的個數
create_time datetime(6)  NOT NULL 插入時間
create_user varchar(50) NOT NULL 操作人

2.2 設計用來保存【各執行步驟詳情】的表

ansible_task_palydetail

欄位名字 欄位類型 預設值 COMMENT
id bigint(20)  NOT NULL AUTO_INCREMENT 主鍵
manager_ip varchar(100)  NOT NULL 管理節點
clustername varchar(200)  NOT NULL 集群名字
playname varchar(360) NOT NULL Ansible劇本名稱
task_serverip varchar(50) NOT NULL Ansible運行節點(受管節點)
taskname varchar(360) NOT NULL 任務名稱
task_status varchar(50) NOT NULL 任務執行結果
task_result_type varchar(10) NOT NULL 執行結果類型(錯誤類型)
task_messages mediumtext NOT NULL Task運行返回信息(錯誤信息)
create_time datetime(6)  NOT NULL 插入時間
create_user varchar(50) NOT NULL 操作人

註意:(1)可以根據需要,在表中增加一列ansible_cmd,用來保存執行的ansible的命令。

        (2)為什麼會有看著奇怪的manager_ip、clustername?因為,這份代碼來自於對DB 集群的 部署 和 管理,可根據實際需要,修改取捨(即你的代碼可以把他們去掉)。

三.Models設計

3.1 AnsiblePlayRecap的定義

class AnsiblePlayRecap(models.Model):
    """
    保存ansible最終執行結果的表
    """
    id = models.AutoField('自增id', primary_key=True)
    manager_ip = models.CharField('MHA Manager IP', max_length=100)
    clustername = models.CharField('HA 集群名字', max_length=200, default='')
    playname = models.CharField('Ansible劇本名稱', max_length=360, default='')
    playrecap_serverip = models.CharField('受管節點', max_length=50, default='')
    playrecap_ok_qty = models.CharField('此節點成功運行的task個數', max_length=10, default='')
    playrecap_changed_qty = models.CharField('產生效果的task個數', max_length=10, default='')
    playrecap_unreachable = models.CharField('相應的遠程節點是否不可達', max_length=10, default='')
    playrecap_failed_qty = models.CharField('執行失敗的task個數', max_length=10, default='')
    playrecap_skipped_qty = models.CharField('跳過的task的個數', max_length=10, default='')
    playrecap_rescued_qty = models.CharField('搶救的task的個數', max_length=10, default='')
    playrecap_ignored_qty = models.CharField('忽略的task的個數', max_length=10, default='')
    create_time = models.DateTimeField('插入時間', auto_now=True)
    create_user = models.CharField('操作人', max_length=50, default='')

    class Meta:
        db_table = 'ansible_play_recap'
        verbose_name = '保存ansible最終執行結果的表'

AnsibleTaskDetail的定義

class AnsibleTaskDetail(models.Model):
    """
    保存各task執行詳情的表
    """
    id = models.AutoField('自增id', primary_key=True)
    manager_ip = models.CharField('MHA Manager IP', max_length=100)
    clustername = models.CharField('HA 集群名字', max_length=200, default='')
    playname = models.CharField('Ansible劇本名稱', max_length=360, default='')
    task_serverip = models.CharField('受管節點', max_length=50, default='')
    taskname = models.CharField('任務名稱', max_length=360, default='')
    task_status = models.CharField('任務執行結果', max_length=50, default='')
    task_result_type = models.CharField('執行結果的錯誤類型', max_length=10, default='')
    task_messages = models.TextField('Task運行返回信息')
    create_time = models.DateTimeField('插入時間', auto_now=True)
    create_user = models.CharField('操作人', max_length=50, default='')

    class Meta:
        db_table = 'ansible_task_palydetail'
        verbose_name = '保存各執行步驟詳情的表'

四.生成SQL腳本

由model所在的項目名稱,通過運行 python manage.py生成

假如項目名稱用XXXX代替

---生成腳本

python manage.py makemigrations XXXX

---顯示剛纔生成的SQL腳本(0006為版本序列號)

python manage.py sqlmigrate XXXX 0006

五. 主要功能代碼

調用代碼,需傳入的參數有三個,

(1)shell_command 餐宿 -----即要執行的Ansible Playbook 命令;

(2)manager_ip參數

(3)cluster_name 參數--- 這兩個命令前面已解釋了,因為我們的這份代碼,其功能是為了維護資料庫集群的。在其他場景下,這兩個參數可以去掉。

5.1 執行ansible 命令

聲明關於正則的模式;連接遠程ansible主機;獲取ansible 執行結果;

    from .ansible import ParamikoHelper
    ##paramiko 是一個用於在Python中執行遠程操作的模塊,支持SSH協議。它可以用於連接到遠程伺服器,執行命令、上傳和下載文件,以及在遠程伺服器上執行各種操作。

    ##字元串中關於IP地址的正則表達式
    ## ^:匹配字元串的開頭。((25[0-5]|2[0-4]\d|[01]?\d\d?)\.):匹配一個數字和一個點號,這個數字的取值範圍是0到255。
    ## {3}:匹配前面的表達式三次。(25[0-5]|2[0-4]\d|[01]?\d\d?):   配一個數字,這個數字的取值範圍是0到255。$:匹配字元串的結尾。
    ## 使用正則表達式匹配IP地址
    # 字元串是IP地址
    ip_pattern = r'^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$'
    ##字元串是IP地址開頭的
    ipstart_pattern = r'^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)'
    ##字元串包含IP
    ipcontain_pattern = r'((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)'   
    ##字元串包含IP,並且IP地址是以': ['字元開頭,以']'字元結尾
    ipcontain_pattern_plus = r'(\: \[)((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}((25[0-5]|2[0-4]\d|[01]?\d\d?)\])' 


    ansible_ip = '你的ansible server IP'
    ssh_port = 你的ssh_port
    ssh_username = '免密登錄設置的賬號'
    ph = ParamikoHelper(remote_ip=ansible_ip,remote_ssh_port=ssh_port,ssh_username=ssh_username)
    stdin, stdout, stderr = ph.exec_shell(shell_command)
    processor_result = stdout.readlines() #readlines()列表形式返回全文,每行作為一個字元串作為列表元素

5.2 開始逐行解析返回的結果

先判斷這一行是否以Server IP開頭(是的話,就是 PLAY RECAP 中的內容 ),

還要判斷這一行 是否 有 以': ['字元開頭,以']'字元結束的Server IP(如果是的話,很可能就是task部分的內容)

兩個判斷是各自獨立的,相互沒有關係依賴。

    ### 先賦值,否則有可能報錯:UnboundLocalError: local variable 'XXXXX' referenced before assignment
    rplayname = ''
    rtask_result_type =''
    ###
    for pr_line in processor_result:
      logger.warning(f'{pr_line}')
      ## 判斷這個字元串是不是以IP地址開頭
      ip_result = re.search(ipstart_pattern, pr_line)
      ## 判斷這個字元串是不是包含IP地址,並且IP以': ['字元開頭,以']'字元結束  
      ip_plus_result = re.search(ipcontain_pattern_plus, pr_line) 
      ##獲取playname start

5.3獲取playname 和taskname

根據是否含有'PLAY ['字元、'TASK ['字元進行判斷和提取。

      ##獲取playname
      if 'PLAY [' in pr_line:
        ##使用的正則表達式'\[(.*?)\]',其中'\'為轉移符,用於表示左右中括弧的匹配,'?'表示非貪婪模式,這個模式會匹配最短的符合要求的字元串。
        ## [0],因正則匹配後,放回的是數組,通過[0],轉換為字元串。
        rplayname = re.findall(r'\[(.*?)\]', pr_line)[0]##獲取task 的名稱
      elif 'TASK [' in pr_line:
        rtaskname = re.findall(r'\[(.*?)\]', pr_line)[0]

5.4 獲取 paly 執行概況

即PLAY RECAP 部分內容,主要依據是這行的字元是以IP地址開頭的。 

      ## 判斷這個字元串是不是以IP地址開頭
      elif ip_result: #字元串是IP地址開頭的
        ## 此時pr_line的字元串格式如下:
        ## pr_line = '172.173.17.18               : ok=5    changed=2    unreachable=1    failed=0    skipped=6    rescued=7    ignored=8'
        rserverip = ip_result.group() ## 匹配的server IP
        ## print(rserverip) ##列印IP地址

        ## 正則表達式,\s+ ,將一個以多個空格或製表符為分隔符的字元串拆分成一個列表
        pr_line_lst = re.split(r"\s+", pr_line)
        ##分割後為: ['172.173.17.18', ':', 'ok=5', 'changed=2', 'unreachable=1', 'failed=0', 'skipped=6', 'rescued=7', 'ignored=8']
        for pr_arry in pr_line_lst:
          if 'ok=' in pr_arry:
            rplayrecap_ok_qty = pr_arry.split("ok=")[1] ##記得:字元串切割後返回的是數組,所以取第二個元素if 'changed=' in pr_arry:
            rplayrecap_changed_qty = pr_arry.split("changed=")[1]if 'unreachable=' in pr_arry:
            rplayrecap_unreachable = pr_arry.split("unreachable=")[1]if 'failed=' in pr_arry:
            rplayrecap_failed_qty = pr_arry.split("failed=")[1]if 'skipped=' in pr_arry:
            rplayrecap_skipped_qty = pr_arry.split("skipped=")[1]if 'rescued=' in pr_arry:
            rplayrecap_rescued_qty = pr_arry.split("rescued=")[1]if 'ignored=' in pr_arry:
            rplayrecap_ignored_qty = pr_arry.split("ignored=")[1]

5.5 將paly 概況數據插入表中

Django 框架,關於Model數據的寫入。

        ### 開始向表[ansible_play_recap]中插入數據,保存ansible最終執行結果的表
        AnsiblePlayRecap.objects.create(manager_ip=manager_ip,clustername=cluster_name,playname=rplayname,playrecap_serverip=rserverip,
                                                    playrecap_ok_qty=rplayrecap_ok_qty,playrecap_changed_qty=rplayrecap_changed_qty,
                                                    playrecap_unreachable=rplayrecap_unreachable,playrecap_failed_qty=rplayrecap_failed_qty,
                                                    playrecap_skipped_qty=rplayrecap_skipped_qty,playrecap_rescued_qty=rplayrecap_rescued_qty,
                                                    playrecap_ignored_qty=rplayrecap_ignored_qty, create_user='Archery System'
                                                    )

5.6 獲取task執行情況,並將數據保存到表中

如果這一行數據包含Server IP地址,並且這個 IP以': ['字元開頭,以']'字元結尾的,那麼這行記錄的就是這個task在某受管節點的執行情況。

      ## 判斷這個字元串是不是包含IP地址,並且IP以': ['字元開頭,以']'字元結尾
      elif ip_plus_result: ##字元串包含IP,並且IP地址是以': ['字元開頭,以']'字元結尾
        if 'ok: [' in pr_line:
          rtask_status = 'ok'
          rtask_messages = '' ## 賦值空
          ##查找server IP
          result = re.search(ipcontain_pattern, pr_line)
          rserverip = result.group() ## 匹配的server IP  
          ## print(rserverip)

        elif 'changed: [' in pr_line:
          rtask_status = 'changed'
          rtask_messages = '' ## 賦值空##查找server IP
          result = re.search(ipcontain_pattern, pr_line)
          rserverip = result.group() ## 匹配的server IP## 有些 返回的change 中還有其他信息,例如:changed: [192.168.168.192] => (item=perl-Parallel-ForkManager-1.18-2.el7.noarch.rpm)
          ## 此時判斷下,是否包含 '] =>',如果包含,賦值給  
          if '] => ' in pr_line:
            rtask_messages= pr_line.split("] => ")[1]elif 'skipping: [' in pr_line:
          rtask_status = 'skipping'
          rtask_messages = '' ## 賦值空
          ##查找server IP
          result = re.search(ipcontain_pattern, pr_line)
          rserverip = result.group() ## 匹配的server IPelif 'fatal: [' in pr_line:
          rtask_status = 'fatal'
          rtask_messages = '' ## 賦值空
          rtask_result_type ='FAILED'##查找server IP
          result = re.search(ipcontain_pattern, pr_line)
          rserverip = result.group() ## 匹配的server IPif 'FAILED! =>' in pr_line:
            rtask_messages= pr_line.split("FAILED! =>")[1]else:
          rtask_status = 'NA'
          rtask_messages = '未知狀態,請DBAcheck......' + pr_line
        ### 開始向表中插入數據
        AnsibleTaskDetail.objects.create(manager_ip=manager_ip,clustername=cluster_name,playname=rplayname,playrecap_serverip=rserverip,
                                                    taskname=rtaskname,task_status=rtask_status,
                                                    task_result_type=rtask_result_type,task_messages=rtask_messages,
                                                    create_user='Archery System'
                                                    )

5.7 去除干擾項和無效項

      elif len(pr_line) == 0 or pr_line == '\n' or ('PLAY RECAP *******' in  pr_line): ###判斷是否空 或只是 簡單的換行符,再或者包含指定字元
           print("這一行為空行 或 說明行,無需記錄!")

5.8 補充有效項

當執行task返回OK時,,後面跟個IP,再後面一般不跟啥了;但是有時候還會由跟東西的。啥時候跟呢? 
例如:task
#debug: # msg: "你想要的返回信息。。。。。。" 這類命令時。
      else:
        rtask_status = 'Mostly OK'
        rtask_result_type = 'debug+msg'   ##'經常出現在task中有debug:msg:的時候'
        rtask_messages =  pr_line
        ### 開始向表中插入數據
        AnsibleTaskDetail.objects.create(manager_ip=manager_ip,clustername=cluster_name,playname=rplayname,playrecap_serverip=rserverip,
                                                    taskname=rtaskname,task_status=rtask_status,
                                                    task_result_type=rtask_result_type,task_messages=rtask_messages,
                                                    create_user='Archery System'
                                                    )

        ###這段處理的情形不好想像,比較難懂,舉個例子
        ## ok: [192.168.168.192] => 
## {
## "msg": "MySQL Replication Health is OK!" ## } ##需要註意的時,相應的在表中也會保留多行數據。因為我們時逐行獲取,逐行解析,逐行報錯的。不過慶幸的時,順序都是對的。

六. 其他說明

6.1 必須說明的是:上面的Python代碼針對的是ansible host 文件保存的是Server IP,如果是功能變數名稱,那麼關於IP的正則是不可用的,代碼必須調整。

6.2  補充幾個task的返回信息的示例,方便理解代碼。

示例 1
ok: [192.168.168.192] => {\n', ' "msg": "MySQL Replication Health is OK!"\n', '}\n 示例 2 changed: [192.168.168.192] => (item=perl-Parallel-ForkManager-1.18-2.el7.noarch.rpm)
示例 3
fatal: [192.168.168.192]: FAILED! => {"changed": false, "msg": "No package matching "test" found available, installed or updated", "rc": 126, "results": ["No package matching "test" found available, installed or updated']}""" 示例 4 skipping: [192.168.168.192]
示例 5
changed: [192.168.168.192]
示例 6
ok: [192.168.168.192]

 6.3 Python讀取Ansible playbooks返回信息只是平臺的一個小功能,整個系統平臺採用的是Django框架。


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

-Advertisement-
Play Games
更多相關文章
  • 說明: Redis是一個開源的,由C語言編寫的高性能NoSQL資料庫,因其高性能、可擴展、相容性強,被各大小互聯網公司或個人作為記憶體型存儲組件使用。 但是其中有小部分公司或個人開發者,為了方便調試或忽略了安全風險,直接用root啟動redis,沒有設置密碼並直接對外開放了6379埠,那麼這就是一個 ...
  • SQL JOIN JOIN子句用於基於它們之間的相關列合併來自兩個或更多表的行。 讓我們看一下“Orders”表的一部分選擇: OrderID CustomerID OrderDate 10308 2 1996-09-18 10309 37 1996-09-19 10310 77 1996-09-2 ...
  • 好基友扔過來一張效果圖,簡單分析下,一起看看如何實現它吧。 一個半環形用於表示 0 - 100%。 半環形開頭有一個圓點作為修飾。 半環形兩端需要呈現為圓角。 通過 div 實現 先畫一個長方形。 <div class="graph"></div> .graph { width: 200px; he ...
  • 這是一本比較冷門的書《設計規則:模塊化的力量》,雖然豆瓣上只有58個評價,但是確實能學到很多東西。 這本書對我非常深遠。不是是投資,創業,還是其他領域,模塊化思想都能幫上你。這本書告訴我們生萬物的規則。 書籍電子版PDF(建議及時保存,避免被和諧):https://pan.quark.cn/s/aa ...
  • 如果在IT行業的時間夠長的話,可能還記得大約10幾年前,設計模式風靡一時的時候,有過一段反 "if" 的運動。 所謂的反"if"運動,其實是誇大了"if"語句帶來的問題,比如當時提出的問題有: 代碼不好維護,特別是if或者else中的代碼比較多的時候 if和 else if分支太多的時候,代碼難以閱 ...
  • 本文首發於公眾號:Hunter後端 原文鏈接:Django筆記四十三之使用uWSGI部署Django系統 目前部署 Django 的方式一般來說是使用 Nginx + uWSGI + Django 來實現。 處理流程是,當一個請求發送過來會先經過 Nginx,如果是靜態文件請求,Nginx 這一層直 ...
  • 在導入包方面,兩者都使用import語句,但是Python沒有類路徑的概念,直接使用文件名來導入模塊。我們還討論了自定義模塊的創建和使用,以及在不同目錄下如何組織代碼結構。此外,我們介紹了一些常用的Python模塊,包括time、datetime、json、os和sys,它們在開發中非常實用。希望今... ...
  • 前言 玩SpringCloud之前最好懂SpringBoot,別搞撐死駱駝的事。Servlet整一下變成Spring;SSM封裝、加入東西就變為SpringBoot;SpringBoot再封裝、加入東西就變為SpringCloud 架構的演進 單體應用架構 單體架構:表示層、業務邏輯層和數據訪問層即 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...