python軟體的開發規範

来源:https://www.cnblogs.com/xiaomage666/archive/2019/05/22/10908856.html
-Advertisement-
Play Games

1.1 軟體的開發規範 什麼是開發規範?為什麼要有開發規範呢? ​ 你現在包括之前寫的一些程式,所謂的'項目',都是在一個py文件下完成的,代碼量撐死也就幾百行,你認為沒問題,挺好。但是真正的後端開發的項目,系統等,少則幾萬行代碼,多則十幾萬,幾十萬行代碼,你全都放在一個py文件中行麽?當然你可以說 ...


1.1 軟體的開發規範

什麼是開發規範?為什麼要有開發規範呢?

​ 你現在包括之前寫的一些程式,所謂的'項目',都是在一個py文件下完成的,代碼量撐死也就幾百行,你認為沒問題,挺好。但是真正的後端開發的項目,系統等,少則幾萬行代碼,多則十幾萬,幾十萬行代碼,你全都放在一個py文件中行麽?當然你可以說,只要能實現功能即可。咱們舉個例子,如果你的衣物只有三四件,那麼你隨便堆在櫥櫃里,沒問題,咋都能找到,也不顯得特別亂,但是如果你的衣物,有三四十件的時候,你在都堆在櫥櫃里,可想而知,你找你穿過三天的襪子,最終從你的大衣口袋裡翻出來了,這是什麼感覺和心情......

  軟體開發,規範你的項目目錄結構,代碼規範,遵循PEP8規範等等,讓你更加清,合理地開發。

那麼接下來我們以博客園系統的作業舉例,將我們之前在一個py文件中的所有代碼,整合成規範的開發。

首先我們看一下,這個是我們之前的目錄結構(簡化版):

py文件的具體代碼如下:

import os

status_dic = {
    'username': None,
    'status': False,
}
flag = True

def login(*args, **kwargs):
    i = 0
    while i < 3:
        username = input('請輸入用戶名:').strip()
        password = input('請輸入密碼:').strip()
        with open('register', encoding='utf-8') as f1:
            for line in f1:
                line_list = line.strip().split('|')
                if username == line_list[0] and password == line_list[1]:
                    status_dic['username'] = username
                    status_dic['status'] = True
                    print('\033[1;32;0m 恭喜您,登錄成功 \033[0m')
                    return True
            else:
                print(f'\033[1;31;0m 賬號或者密碼錯誤,請重新登錄,還剩{2-i}次機會 \033[0m')
                if i == 2: return exit_program()
            i += 1


def register(*args, **kwargs):
    while 1:
        print('\033[1;45m 歡迎來到註冊頁面 \033[0m')
        username = input('請輸入用戶名:').strip()
        with open('register', encoding='utf-8') as f1:
            for line in f1:
                if username == line.split('|')[0].strip():
                    print('\033[1;31;0m 用戶名已存在,請重新輸入 \033[0m')
                    continue
        if not username.isalnum():
            print('\033[1;31;0m 用戶名有非法字元,請重新輸入 \033[0m')
            continue
        password = input('請輸入密碼:').strip()
        if 6 <= len(password) <= 14:
            with open('register', encoding='utf-8',mode='a') as f1:
                f1.write(f'\n{username}|{password}')
            status_dic['username'] = username
            status_dic['status'] = True
            print('\033[1;32;0m 恭喜您,註冊成功!已幫您成功登錄~ \033[0m')
            return True
        else:
            print('\033[1;31;0m 密碼長度超出範圍,請重新輸入 \033[0m')
            
        
def auth(func):
    
    def inner(*args, **kwargs):
        if status_dic['status']:
            ret = func(*args, **kwargs)
            return ret
        else:
            print( '\033[1;31;0m 請先進行登錄 \033[0m')
            if login():
                ret = func(*args, **kwargs)
                return ret

    return inner


@auth
def article():
    print(f'\033[1;32;0m 歡迎{status_dic["username"]}訪問文章頁面\033[0m')

        
@auth
def diary():
    print(f'\033[1;32;0m 歡迎{status_dic["username"]}訪問日記頁面\033[0m')


@auth
def comment():
    print(f'\033[1;32;0m 歡迎{status_dic["username"]}訪問評論頁面\033[0m')
   
    
@auth
def enshrine():
    print(f'\033[1;32;0m 歡迎{status_dic["username"]}訪問收藏頁面\033[0m')


def login_out():
    status_dic['username'] = None
    status_dic['status'] = False
    print('\033[1;32;0m 註銷成功 \033[0m')


def exit_program():
    global flag
    flag = False
    return flag


choice_dict = {
    1: login,
    2: register,
    3: article,
    4: diary,
    5: comment,
    6: enshrine,
    7: login_out,
    8: exit_program,
}

while flag:
    print('''
    歡迎來到博客園首頁
    1:請登錄
    2:請註冊
    3:文章頁面
    4:日記頁面
    5:評論頁面
    6:收藏頁面
    7:註銷
    8:退出程式''')
    
    choice = input('請輸入您選擇的序號:').strip()
    if choice.isdigit():
        choice = int(choice)
        if 0 < choice <= len(choice_dict):
            choice_dict[choice]()
        else:
            print('\033[1;31;0m 您輸入的超出範圍,請重新輸入 \033[0m')

    else:
        print('\033[1;31;0m 您您輸入的選項有非法字元,請重新輸入 \033[0m')

此時我們是將所有的代碼都寫到了一個py文件中,如果代碼量多且都在一個py文件中,那麼對於代碼結構不清晰,不規範,運行起來效率也會非常低。所以我們接下來一步一步的修改:

【1】 程式配置。

你項目中所有的有關文件的操作出現幾處,都是直接寫的register相對路徑,如果說這個register註冊表路徑改變了,或者你改變了register註冊表的名稱,那麼相應的這幾處都需要一一更改,這樣其實你就是把代碼寫死了,那麼怎麼解決? 我要統一相同的路徑,也就是統一相同的變數,在文件的最上面寫一個變數指向register註冊表的路徑,代碼中如果需要這個路徑時,直接引用即可。

【2】 劃分文件。

一個項目的函數不能只是這些,我們只是舉個例子,這個小作業函數都已經這麼多了,那麼要是一個具體的實際的項目,函數會非常多,所以我們應該將這些函數進行分類,然後分文件而治。在這裡我劃分了以下幾個文件:

settings.py: 配置文件,就是放置一些項目中需要的靜態參數,比如文件路徑,資料庫配置,軟體的預設設置等等。

類似於我們作業中的這個:

common.py:公共組件文件,這裡面放置一些我們常用的公共組件函數,並不是我們核心邏輯的函數,而更像是服務於整個程式中的公用的插件,程式中需要即調用。比如我們程式中的裝飾器auth,有些函數是需要這個裝飾器認證的,但是有一些是不需要這個裝飾器認證的,它既是何處需要何處調用即可。比如還有密碼加密功能,序列化功能,日誌功能等這些功能都可以放在這裡。

src.py:這個文件主要存放的就是核心邏輯功能,你看你需要進行選擇的這些核心功能函數,都應該放在這個文件中。

start.py:項目啟動文件。你的項目需要有專門的文件啟動,而不是在你的核心邏輯部分進行啟動的,有人對這個可能不太理解,我為什麼還要設置一個單獨的啟動文件呢?你看你生活中使用的所有電器基本都一個單獨的啟動按鈕,汽車,熱水器,電視,等等等等,那麼為什麼他們會單獨設置一個啟動按鈕,而不是在一堆線路板或者內部隨便找一個地方開啟呢? 目的就是放在顯眼的位置,方便開啟。你想想你的項目這麼多py文件,如果src文件也有很多,那麼到底哪個文件啟動整個項目,你還得一個一個去尋找,太麻煩了,這樣我把它單獨拿出來,就是方便開啟整個項目。

那麼我們寫的項目開啟整個項目的代碼就是下麵這段:

你把這些放置到一個文件中也可以,但是沒有必要,我們只需要一個命令或者一個開啟指令就行,就好比我們開啟電視只需要讓人很快的找到那個按鈕即可,對於按鈕後面的一些複雜的線路板,我們並不關心,所以我們要將上面這個段代碼整合成一個函數,開啟項目的''按鈕''就是此函數的執行即可。

這個按鈕要放到啟動文件start.py裡面。

除了以上這幾個py文件之外還有幾個文件,也是非常重要的:

類似於register文件:這個文件文件名不固定,register只是我們項目中用到的註冊表,但是這種文件就是存儲數據的文件,類似於文本資料庫,那麼我們一些項目中的數據有的是從資料庫中獲取的,有些數據就是這種文本資料庫中獲取的,總之,你的項目中有時會遇到將一些數據存儲在文件中,與程式交互的情況,所以我們要單獨設置這樣的文件。

log文件:log文件顧名思義就是存儲log日誌的文件。日誌我們一會就會講到,日誌主要是供開發人員使用。比如你項目中出現一些bug問題,比如開發人員對伺服器做的一些操作都會記錄到日誌中,以便開發者瀏覽,查詢。

至此,我們將這個作業原來的兩個文件,合理的劃分成了6個文件,但是還是有問題的,如果我們的項目很大,你的每一個部分相應的你一個文件存不下的,比如你的src主邏輯文件,函數很多,你是不是得分成:src1.py src2.py?

你的文本資料庫register這個只是一個註冊表,如果你還有個人信息表,記錄表呢? 如果是這樣,你的整個項目也是非常凌亂的:

​【3】劃分具體目錄

上面看著就非常亂了,那麼如何整改呢? 其實非常簡單,原來你就是30件衣服放在一個衣櫃里,那麼你就得分類裝,放外套的地方,放內衣的地方,放佩飾的地方等等,但是突然你的衣服編程300件了,那一個衣櫃放不下,我就整多個柜子,分別放置不同的衣物。所以我們這可以整多個文件夾,分別管理不同的物品,那麼標準版本的目錄結構就來了:

為什麼要設計項目目錄結構?

"設計項目目錄結構",就和"代碼編碼風格"一樣,屬於個人風格問題。對於這種風格上的規範,一直都存在兩種態度:

  1. 一類同學認為,這種個人風格問題"無關緊要"。理由是能讓程式work就好,風格問題根本不是問題。
  2. 另一類同學認為,規範化能更好的控製程序結構,讓程式具有更高的可讀性。

我是比較偏向於後者的,因為我是前一類同學思想行為下的直接受害者。我曾經維護過一個非常不好讀的項目,其實現的邏輯並不複雜,但是卻耗費了我非常長的時間去理解它想表達的意思。從此我個人對於提高項目可讀性、可維護性的要求就很高了。"項目目錄結構"其實也是屬於"可讀性和可維護性"的範疇,我們設計一個層次清晰的目錄結構,就是為了達到以下兩點:

  1. 可讀性高: 不熟悉這個項目的代碼的人,一眼就能看懂目錄結構,知道程式啟動腳本是哪個,測試目錄在哪兒,配置文件在哪兒等等。從而非常快速的瞭解這個項目。
  2. 可維護性高: 定義好組織規則後,維護者就能很明確地知道,新增的哪個文件和代碼應該放在什麼目錄之下。這個好處是,隨著時間的推移,代碼/配置的規模增加,項目結構不會混亂,仍然能夠組織良好。

所以,我認為,保持一個層次清晰的目錄結構是有必要的。更何況組織一個良好的工程目錄,其實是一件很簡單的事兒。

上面那個圖片就是較好的目錄結構。

1.2 按照項目目錄結構,規範博客園系統

接下來,我就帶領大家把具體的代碼寫入對應的文件中,並且將此項目啟動起來,一定要跟著我的步驟一步一步去執行:

【1】 配置start.py文件

​ 我們首先要配置啟動文件,啟動文件很簡答就是將項目的啟動執行放置start.py文件中,運行start.py文件可以成功啟動項目即可。 那麼項目的啟動就是這個指令run() 我們把這個run()放置此文件中不就行了?

這樣你能執行這個項目麽?肯定是不可以呀,你的starts.py根本就找不到run這個變數,肯定是會報錯的。

​ NameError: name 'run' is not defined 本文件肯定是找不到run這個變數也就是函數名的,不過這個難不倒我們,我們剛學了模塊, 另個一文件的內容我們可以引用過來。但是你發現import run 或者 from src import run 都是報錯的。為什麼呢? 騷年,遇到報錯不要慌!我們說過你的模塊之所以可以引用,那是因為你的模塊肯定在這個三個地方:記憶體,內置,sys.path裡面,那麼core在記憶體中肯定是沒有的,也不是內置,而且sys.path也不可能有,因為sys.path只會將你當前的目錄(bin)載入到記憶體,所以你剛纔那麼引用肯定是有問題的,那麼如何解決?記憶體,內置你是左右不了的,你只能將core的路徑添加到sys.path中,這樣就可以了。

import sys
sys.path.append(r'D:\lnh.python\py project\teaching_show\blog\core')
from src import run
run()

這樣雖然解決了,但是你不覺得有問題麽?你現在從這個start文件需要引用src文件,那麼你需要手動的將src的工作目錄添加到sys.path中,那麼有沒有可能你會引用到其他的文件?比如你的項目中可能需要引用conf,lib等其他py文件,那麼在每次引用之前,或者是開啟項目時,全部把他們添加到sys.path中麽?

sys.path.append(r'D:\lnh.python\py project\teaching_show\blog\core')
sys.path.append(r'D:\lnh.python\py project\teaching_show\blog\conf')
sys.path.append(r'D:\lnh.python\py project\teaching_show\blog\db')
sys.path.append(r'D:\lnh.python\py project\teaching_show\blog\lib')

這樣是不是太麻煩了? 我們應該怎麼做?我們應該把項目的工作路徑添加到sys.path中,用一個例子說明:你想找張三,李四,王五,趙六等人,這些人全部都在一棟樓比如在匯德商廈,那麼我就告訴你匯德大廈的位置:北京xx區xx鎮匯德大廈。 你到了匯德大廈你在找具體這些人就可以了。所以我們只要將這個blog項目的工作目錄添加到sys.path中,這樣無論這個項目中的任意一個文件引用項目中哪個文件,就都可以找到了。所以:

import sys
sys.path.append(r'D:\lnh.python\py project\teaching_show\blog')
from core.src import run
run()

上面還是差一點點,你這樣寫你的blog的路徑就寫死了,你的項目不可能只在你的電腦上,項目是共同開發的,你的項目肯定會出現在別人電腦上,那麼你的路徑就是問題了,在你的電腦上你的blog項目的路徑是上面所寫的,如果移植到別人電腦上,他的路徑不可能與你的路徑相同, 這樣就會報錯了,所以我們這個路徑要動態獲取,不能寫死,所以這樣就解決了:

import sys
import os
# sys.path.append(r'D:\lnh.python\py project\teaching_show\blog')
print(os.path.dirname(__file__))
# 獲取本文件的絕對路徑  # D:/lnh.python/py project/teaching_show/blog/bin
print(os.path.dirname(os.path.dirname(__file__)))
# 獲取父級目錄也就是blog的絕對路徑  # D:/lnh.python/py project/teaching_show/blog
BATH_DIR = os.path.dirname(os.path.dirname(__file__))
sys.path.append(BATH_DIR)
from core.src import run
run()

那麼還差一個小問題,這個starts文件可以當做腳本文件進行直接啟動,如果是作為模塊,被別人引用的話,按照這麼寫,也是可以啟動整個程式的,這樣合理麽?這樣是不合理的,作為啟動文件,是不可以被別人引用啟動的,所以我們此時要想到 __name__了:

import sys
import os
# sys.path.append(r'D:\lnh.python\py project\teaching_show\blog')
# print(os.path.dirname(__file__))
# 獲取本文件的絕對路徑  # D:/lnh.python/py project/teaching_show/blog/bin
# print(os.path.dirname(os.path.dirname(__file__)))
# 獲取父級目錄也就是blog的絕對路徑  # D:/lnh.python/py project/teaching_show/blog
BATH_DIR = os.path.dirname(os.path.dirname(__file__))
sys.path.append(BATH_DIR)
from core.src import run

if __name__ == '__main__':
    run()

這樣,我們的starts啟動文件就已經配置成功了。以後只要我們通過starts文件啟動整個程式,它會先將整個項目的工作目錄添加到sys.path中,然後在啟動程式,這樣我整個項目裡面的任何的py文件想引用項目中的其他py文件,都是你可以的了。

【2】配置settings.py文件

接下來,我們就會將我們項目中的靜態路徑,資料庫的連接設置等等文件放置在settings文件中。

我們看一下,你的主邏輯src中有這樣幾個變數:

status_dic = {
    'username': None,
    'status': False,
}
flag = True
register_path = r'D:\lnh.python\py project\teaching_show\blog\register'

我們是不是應該把這幾個變數都放置在settings文件中呢?不是!setttings文件叫做配置文件,其實也叫做配置靜態文件,什麼叫靜態? 靜態就是一般不會輕易改變的,但是對於上面的代碼status_dic ,flag這兩個變數,由於在使用這個系統時會時長變化,所以不建議將這個兩個變數放置在settings配置文件中,只需要將register_path放置進去就可以。

register_path = r'D:\lnh.python\py project\teaching_show\blog\register'

但是你將這個變數放置在settings.py之後,你的程式啟動起來是有問題,為什麼?

    with open(register_path, encoding='utf-8') as f1:
NameError: name 'register_path' is not defined

因為主邏輯src中找不到register_path這個路徑了,所以會報錯,那麼我們解決方式就是在src主邏輯中引用settings.py文件中的register_path就可以了。

這裡引發一個問題:為什麼你這樣寫就可以直接引用settings文件呢?我們在starts文件中已經說了,剛已啟動blog文件時,我們手動將blog的路徑添加到sys.path中了,這就意味著,我在整個項目中的任何py文件,都可以引用到blog項目目錄下麵的任何目錄:bin,conf,core,db,lib,log這幾個,所以,剛纔我們引用settings文件才是可以的。

【3】 配置common.py文件

接下來,我們要配置我們的公共組件文件,在我們這個項目中,裝飾器就是公共組件的工具,我們要把裝飾器這個工具配置到common.py文件中。先把裝飾器代碼剪切到common.py文件中。這樣直接粘過來,是有各種問題的:

所以我們要在common.py文件中引入src文件的這兩個變數。

可是你的src文件中使用了auth裝飾器,此時你的auth裝飾器已經移動位置了,所以你要在src文件中引用auth裝飾器,這樣才可以使用上。

OK,這樣你就算是將你之前寫的模擬博客園登錄的作業按照規範化目錄結構合理的完善完成了,最後還有一個關於README文檔的書寫。

關於README的內容

這個我覺得是每個項目都應該有的一個文件,目的是能簡要描述該項目的信息,讓讀者快速瞭解這個項目。

它需要說明以下幾個事項:

  1. 軟體定位,軟體的基本功能。
  2. 運行代碼的方法: 安裝環境、啟動命令等。
  3. 簡要的使用說明。
  4. 代碼目錄結構說明,更詳細點可以說明軟體的基本原理。
  5. 常見問題說明。

我覺得有以上幾點是比較好的一個README。在軟體開發初期,由於開發過程中以上內容可能不明確或者發生變化,並不是一定要在一開始就將所有信息都補全。但是在項目完結的時候,是需要撰寫這樣的一個文檔的。

可以參考Redis源碼中Readme的寫法,這裡面簡潔但是清晰的描述了Redis功能和源碼結構。


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

-Advertisement-
Play Games
更多相關文章
  • 爬蟲要想爬取需要的信息,首先第一步就要抓取到頁面html內容,然後對html進行分析,獲取想要的內容。上一篇隨筆《Java爬蟲系列一:寫在開始前》中提到了HttpClient可以抓取頁面內容。 今天就來介紹下抓取html內容的工具:HttpClient。 圍繞下麵幾個點展開: 什麼是HttpClie ...
  • Set集合 哈希值 Set集合存儲元素不重覆的原理 Set集合在調用add方法的時候,add方法會調用元素的hashCode方法和equals方法,判斷元素是否重覆,若hashCode和equals都相同則不添加到集合,要保證hashCode和equals不同必須重寫hashCode和equals方 ...
  • 創建SpringApplication對象 SpringBoot版本為 2.1.1.RELEASE @SpringBootApplication public class SpringbootDemoApplication { public static void main(String[] arg ...
  • 反爬蟲之搭建IP代理池 聽說你又被封 ip 了,你要學會偽裝好自己,這次說說偽裝你的頭部。可惜加了header請求頭,加了cookie 還是被限制爬取了。這時就得祭出IP代理池!!! 下麵就是requests使用ip代理例子 這樣就可以使用你定義的代理地址去訪問網站了 但IP代理哪裡來阿?有兩種方式 ...
  • array_merge是很常用的數組合併函數,但是兩個數組直接相加對開發也是很有幫助的,兩者之間有什麼差別,這裡記錄一下~ ...
  • 測試題答案: 0. 什麼是BIF?BIF 就是 Built-in Functions,內置函數。為了方便程式員快速編寫腳本程式(腳本就是要編程速度快快快!!!),Python 提供了非常豐富的內置函數,我們只需要直接調用即可,例如 print() 的功能是“列印到屏幕”,input() 的作用是接收 ...
  • 測試題答案: 0. Python 是什麼類型的語言? Python是腳本語言 腳本語言(Scripting language)是電腦編程語言,因此也能讓開發者藉以編寫出讓電腦聽命行事的程式。以簡單的方式快速完成某些複雜的事情通常是創造腳本語言的重要原則,基於這項原則,使得腳本語言通常比 C語言、C+ ...
  • # coding=utf-8import randomprint("猜數字游戲開始\n")count = 0count1 = 0guessact = random.randint(5, 15)print("猜數提示:取值範圍5-15,整數值\n")while 1 == 1: guess = int( ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...