WEB API 設計規范

REST API 簡介

REST 是 Representational State Transfer 的縮寫,它將資源作為核心概念,通過 HTTP 方法對資源進行操作。其本身是一套圍繞資源進行操作的架構規范。在實際應用中,更多的是體現在 API 的設計上。

企業在進行產品設計開發時,通常首先由業務專家和技術專家一起梳理出業務模型,然后根據領域驅動設計(DDD)的方法論進行建模,設計出領域模型以及針對領域模型的操作。最終,這些領域模型會映射為數據存儲的數據模型以及 REST API 的資源模型,而針對領域模型的操作會映射為 HTTP 方法以及 REST API 的 Action。

REST API 幾乎已經是互聯網服務 Web API 設計的事實標準,根據 Google 的 API 設計指南,早在 2010 年,就有大約 74% 的公共網絡 API 是 HTTP REST(或類似 REST)風格的設計,大多數 API 均使用 JSON 作為傳輸格式。

RESTful 設計原則

滿足 REST 要求的架構需遵循以下6個設計原則:

1. 客戶端與服務端分離

目的是將客戶端和服務端的關注點分離。在 Web 應用中,將用戶界面所關注的邏輯和服務端數據存儲所關注的邏輯分離開來,有助于提高客戶端的跨平臺的可移植性;也有助于提高服務端的可擴展性。

隨著前端技術的發展,前后端分離已經是主流的開發方式,傳統的 Spring MVC/Django 的前端模板渲染已經被逐漸棄用了。

2. 無狀態

服務端不保存客戶端的上下文信息,會話信息由客戶端保存,服務端根據客戶端的請求信息處理請求。

在實際開發中,服務端通常會保存一些狀態信息,比如會話信息、認證信息等,這些信息一般是保存在服務端的數據庫或者緩存中。

3. 可緩存

這一條算是上一條的延伸,無狀態服務提升了系統的可靠性、可擴展性,但也會造成不必要的網絡開銷。為了緩解這個問題,REST 要求客戶端或者中間代理(網關)能緩存服務端的響應數據。服務端的響應信息必須明確表示是否可以被緩存以及緩存的時長,以避免客戶端請求到過期數據。

管理良好的緩存機制可以有效減少客戶端-服務器之間的交互,甚至完全避免客戶端-服務器交互,從而提升了系統的性能和可擴展性。

4. 分層系統

對于客戶端來說,中間代理是透明的。客戶端無需知道請求路徑中代理、網關、負載均衡等中間件的存在,這樣可以提高系統的可擴展性和安全性。

5. 統一接口

REST 要求開發者面向資源來設計系統,有下面四個約束:

  • 每次請求中都包含資源 ID

  • 所有操作均等通過資源 ID 進行

  • 消息是自描述的:每條消息包含足夠的信息來描述如何處理這條消息。比如 mime 標識媒體類型,content-type 標識編碼格式,language 標識語言,charset 標識字符集,encoding 標識壓縮格式等。

  • 用超媒體驅動應用狀態(HATEOAS,Hypermedia as the Engine of Application State):客戶端在訪問了最初的 REST API 后,服務端會返回后續操作的鏈接,客戶端使用服務端提供的鏈接動態的發現可用資源和可執行操作。

6. 按需編碼(可選)

這是一條可選約束,指的是服務端可以根據客戶端需求,將可執行代碼發送給客戶端,從而實現臨時性的功能擴展或定制功能,比如以前的 Java Applet。

REST API 成熟度模型

上述約束讀起來還是有些抽象,鑒于在實際開發中,我們更多是聚焦在 API 設計上。為了衡量一個系統是否符合 REST 風格,《RESTful Web APIs》和《RESTful Web Services》的作者 Leonard Richardson 提出了 REST 成熟度模型,根據 API 的設計風格將其分為了 4 級。

第 0 級: 完全不符合 REST 風格

比如 RPC 面向過程的 API 設計基本是圍繞操作過程來設計的,完全沒有資源的概念。

下面是 Martin Fowler 在介紹成熟度模型的 blog Richardson Maturity Model 中舉的病人預約的例子,病人首先需要查詢醫生可預約的時間表,然后提交預約。

查詢預約服務時提交的請求為

POST /appointmentService?action=query HTTP/1.1{"date": "2020-03-04","doctor": "mjones"
}

請求成功后響應如下

HTTP/1.1 200 OK
[{"start": "14:00","end": "14:50","doctor": "mjones"},{"start": "16:00","end": "16:50","doctor": "mjones"}
]

然后病人選擇時段提交預約

POST /appointmentService?action=confirm HTTP/1.1{"slot": {"start": "14:00","end": "14:50","doctor": "mjones"},"patient": {"id": "jsmith"}
}

預定成功時響應如下

HTTP/1.1 200 OK{"slot": {"start": "14:00","end": "14:50","doctor": "mjones"},"patient": {"id": "jsmith"}
}

預定失敗時響應如下

HTTP/1.1 200 OK{"slot": {"start": "14:00","end": "14:50","doctor": "mjones"},"patient": {"id": "jsmith"},"reason": "Slot not available"
}

可以看到整個請求過程沒有涉及到資源的概念,并且請求也比較簡潔明了。但如果操作越來越多,接口也越來越多,隨之而來的維護、溝通成本也會越來越高。

第 1 級:引入資源概念

引入資源后,對服務端的訪問都是圍繞資源,通過資源 ID 進行。此時的查詢和預約請求如下:

查詢預約:以醫生為資源,通過 ID查詢

POST /doctors/mjones HTTP/1.1{date: "2020-03-04"}// 請求響應[{"slot_id": 1234, doctor: "mjones", start: "14:00", end: "14:50"},{"slot_id": 5678, doctor: "mjones", start: "16:00", end: "16:50"}
]

提交預約時,以時間表 slot 為資源,通過 ID 預約

POST /slots/1234 HTTP/1.1{ "patient_id": "jsmith" }
第 2 級:操作映射到 HTTP 方法

上面的例子中所有請求都是用的 POST 方法,Level2 要求將操作映射到 HTTP 方法。對于資源的操作無非就是增刪改查,HTTP 對應的 POST、DELETE、PUT/PATCH、GET 可以很好的表達這些操作。

  • 查詢檔期,使用 GET 方法
GET /doctors/mjones/schedule?date=2020-03-04&status=open HTTP/1.[{"slot_id": 1234, doctor: "mjones", start: "14:00", end: "14:50"},{"slot_id": 5678, doctor: "mjones", start: "16:00", end: "16:50"}
]
  • 創建預約,使用 POST 方法
POST /schedules/1234 HTTP/1.1{ "patient_id": "jsmith" }
// 預定成功響應
HTTP/1.1 201 Created
Location: slots/1234/appointment{"slot": {"id": 1234,"doctor": "mjones","start": "14:00","end": "14:50"},"patient": {"id": "jsmith"}
}

預定失敗時,需要返回能表達錯誤原因的響應碼,而不是像之前一樣返回 200。

HTTP/1.1 409 Conflict[{"slot_id": 5678, doctor: "mjones", start: "16:00", end: "16:50"}  
]

第2級是目前絕大多數系統所達到的級別。

第 3 級:狀態轉移完全由后端驅動

在實際開發中,通常是客戶端和服務端約定好 API 后進行各自的實現。客戶端在代碼中已經編寫了 API 相關的調用,但 REST 認為這是多余的,客戶端應該根據服務端返回的鏈接進行后續操作,返回的資源信息以及操作鏈接信息能夠描述自身以及后續可能發生的狀態轉移,從而實現超文本驅動應用狀態。

依然是查詢預約的 API,此時后端返回的預約列表,除了基本信息外還帶有預約所需 link,由此客戶端知曉后續的預約操作,并請求服務端返回的 link 進行操作。

GET /doctors/mjones/slots?date=20100104&status=open HTTP/1.1[{"slot_id": 1234, doctor: "mjones", start: "14:00", end: "14:50", links: [{"rel": "book", "href": "/slots/1234"}]},{"slot_id": 5678, doctor: "mjones", start: "16:00", end: "16:50", links: [{"rel": "book", "href": "/slots/5678"}]}
]

可以看到返回的數據中包含了支持的預約操作以及操作所對應的鏈接。

REST VS RPC

API 的設計通常有 RPC 和 REST 兩種形式。雖然兩者并不是一回事,但因為都是面向服務端和客戶端的通信制定規范,所以經常被混為一談。

REST 本身一套面向資源的架構設計思想,而 RPC 的初衷是希望能在分布式系統之間,像調用本地方法一樣調用遠程方法,圍繞通信過程實現進行的一系列實現。RPC 協議也是層出不窮,針對數據的編碼、傳輸以及方法的表達提供不同的解決方案。關于 RPC 更多的講解可以參考鳳凰架構:遠程服務調用。

具體到 API 設計上,其主要區別在于:REST 是面向資源的,而 RPC 是面向過程的。以一個用戶的增刪改查為例,REST 的 API 設計如下

# 創建用戶
POST /users
# 查詢用戶列表
GET /users  
# 查詢用戶詳情
GET /users/{id}
# 更新用戶信息
PUT /users/{id}
# 刪除用戶
DELETE /users/{id}

而 RPC 的 API 設計如下:

# 創建用戶
POST /createUser
# 查詢用戶列表
GET /getUserList
# 查詢用戶詳情
GET /getUserById
# 更新用戶信息
PUT /updateUser
# 刪除用戶
DELETE /deleteUser

URI 的設計規范

了解了 REST API 的一些基本概念,下面我們看下可以在實踐中應用的 URI設計規范。

根據 RFC 3986 - - Uniform Resource Identifier (URI): Generic Syntax 中的定義,一個 URI 的結構如下所示:

       foo://example.com:8042/over/there?name=ferret#nose\_/   \______________/\_________/ \_________/\__/|        |              |          |          |
scheme(協議)authority(域名) path(路徑) query(查詢參數)fragment(片段)

我們這里主要針對 path 和 query 部分進行討論,對于 PATH 我們可以使用如下規范形式:

{domain}/{version}/{appid}/{resource}
{domain}/{version}/{appid}/{resource}/{sub-resource}/
{domain}/{version}/{appid}/{resource}/{action}

URI 主體字段含義

首先來看下 URL 中各個字段的含義與設計規范。

  • {domain} 表示 API 的域名。可以使用統一的域名,也可以針對不同的業務線使用不同的域名。
  • {version} 表示 API 的版本。形式是 v + 數字,比如 v1, v2,有特殊需求是也可以進一步區分主版本和子版本,比如 v1.1, v1.2。一般只有在接口不兼容時才會升級。
  • {appid} 服務的唯一標識。比如 order 表示訂單服務,user 表示用戶服務,payment 表示支付服務。
  • {resource} 具體的資源,要用名詞且為復數形式。比如 orders 表示訂單資源,users 表示用戶資源,payments 表示支付資源。
  • {sub-resource} 子資源,操作場景下和資源有依賴關系,要用名詞且為復數形式。比如購物車和購物車項。
  • {action} 針對資源或子資源的行為操作,用動詞或者動詞短語表示,用來彌補 HTTP 方法表達上的不足。

URI 路徑規范

1. URI 中所有命名必須是小寫英文

下面是一個不規范的實例,使用了大寫字或非英文字母。

https://api.server.com/v1/訂單/orders 
https://api.server.com/v1/PAYMENT/records
https://api.server.com/v1/order/orders/REFUND
2. URI 路徑分隔符推薦使用中劃線 -

下面是一個使用 _ 的不規范實例

https://api.server.com/v1/marketing/coupons/get_by_code
3. URI 路徑中查詢參數命名必須統一使用 snake_case 或 camelCase 風格

在實踐中筆者通常傾向于統一使用 snake_case 風格,但有的團隊也會使用駝峰命名法。這里重要的是保持統一,避免在進行 API 設計時因為風格不一致導致不必要的溝通成本。

下面是一個使用 snake_case 風格的 URI:

https://api.server.com/v1/marketing/coupons/get-by-merchants?merchant_id=123456

下面是一個使用 camelCase 風格的 URI:

https://api.server.com/v1/marketing/coupons/getByMerchants?merchantId=123456

下面是一個使用駝峰命名法的不規范 URI,首字母用了大寫:

https://api.server.com/v1/marketing/coupons/get-by-merchants?MerchantId=123456
4. URI 中禁止出現 CURD 動詞,應該映射到 HTTP 方法

下面是一個不合法的 URI 示例,使用了 CURD 動詞:

GET /doctors/mjones/get-schedules

如果有特殊需求,應該有更明確的語義表達,但 Get、List、Update、Delete 這些 CURD 應該盡量避免。

5. URI 的路徑和參數必須以標準 UTF-8 編碼

比如出現漢字、空格、特殊符號等字符時,需要進行編碼。

6. URI 長度限制

RFC7230 中并沒有對 URI 的長度進行限制,但在實際開發中,最好限制在 2048 以內。如果 URI 過程,需要返回 HTTP 414 狀態碼(URI Too Long)。[參考 Stackoverflow]。

7. 資源 ID 規范

資源 ID 必須放到資源的后面,并且盡可能使用 UUID、HMAC 等類型的 ID,而不是數據庫的自增主鍵 ID,避免被人通過主鍵 ID 爬數據。比如

https://api.server.com/v1/payment/orders/298f37e-a538-11e9-93e8-0b39560ac73d
7. 子資源使用規范

只有在 API 操作場景下,子資源和資源有依賴關系時,才使用子資源。大致有兩類情況:

  • 子資源不能獨立存在,必須依附于上級主資源訪問。比如某個用戶的簡歷信息,必須依附在某個用戶下。

  • 子資源不能獨立表達含義。比如社交系統用的用戶和好友資源。可能最終訪問的是同一張數據表,但在用戶操作場景下可以獨立存在,而在好友場景下是依附于用戶存在的。

  • 查詢用戶信息

# 查詢用戶詳情
GET .../users/1# 查詢用戶簡歷信息
GET .../users/1/resume# 查詢用戶好友
GET .../users/1/friends

在使用子資源時需要注意嵌套層級,盡可能不要使用超過 3 層的嵌套。

  • 過多的嵌套會導致 API 過于復雜,不易理解
  • 多級資源容易導致 URI 過長,引起一些兼容性問題。
8. 動詞使用規范

對資源的增刪改查應該使用標準的 HTTP 方法,比如 GET、POST、PUT、DELETE。下面是 HTTP 方法于操作的映射關系:

REST API 要求對資源的操作應該與 HTTP 方法對應,下面是資源操作的標準方法與映射關系。

資源操作HTTP 方法描述是否冪等是否支持 Body響應格式
ListGET用于查詢操作,對應數據庫的 select 操作???資源列表,無數據時返回空列表
GetGET用于查詢操作,對應數據庫的 select 操作???資源詳情,無數據時返回 404
UpdatePUT用于所有的信息更新,對應數據庫的 update 操作????資料詳情
DeleteDELETE用于更新操作,對應數據庫的 delete 操作???
CreatePOST用于新增操作,對應數據庫的 insert 操作???資源詳情
HEAD用于返回一個資源對象的“元數據”,或是用于探測API是否健康???資源詳情
UPDATEPATCH用于局部信息的更新,對應于數據庫的 update 操作??資源詳情
OPTIONS獲取API的相關的信息。???

以下是基本的 API 示例

// 創建用戶
POST /users//查詢用戶列表
GET /users// 查詢用戶詳情
GET /users/1// 更新用戶信息
PUT /users/1// 刪除用戶
DELETE /users/1

如果有特殊的動作可以在路徑中使用 action 來標識,action 必須是動詞性質的單詞或短語。比如

# 實名認證
POST /users/1/real-name-auth# 取消訂單
PUT /orders/123456/cancel# 激活優惠券
PUT /coupons/123456/activate

常用標準字段

API 中通常有許多通用字段,比如名稱,排序,分頁,時間戳等,下面是一些常用的標準字段和相關規范。

字段名類型說明
namestring資源名稱
parentstring父資源名稱
create_timetimestamp創建時間
create_bystring創建者
update_timetimestamp更新時間
update_bystring更新者
delete_timetimestamp刪除時間
delete_bystring刪除者
expire_timetimestamp過期時間
start_timetimestamp開始時間
end_timetimestamp結束時間
time_zonestring時區名稱, 取值應遵從 Time Zone Database 中給出的時區名稱
region_codestring地區編碼,取值應遵從 unicode_region_subtag 標準
language_codestring語言編碼,取值應遵從 Unicode_Language_and_Locale_Identifiers
currency_codestring貨幣編碼,取值應遵從 ISO 4217 標準
mime_typestring媒體類型,取值應遵從 Mime 類型 標準
page_sizeint32分頁大小
page_numberint32分頁頁碼
total_sizeint32數據總數
total_pageint32數據總頁數
sort/order_bystring排序字段
asc/descstring排序順序
filterstring過濾器參數
and、or、not過濾器表達式要支持的邏輯操作符
=,!=,>,<,>=,<=過濾器表達式要支持的比較操作符,實際使用中有時也用單詞表示:eq,ne,gt,lt,ge,le 表示
search/querystring搜索參數
sort_orderstring排序順序,取值為 asc 或 desc
create_bystring創建者
update_bystring更新者
statusstring狀態
remarkstring備注

HTTP 規范

Header 規范

應該盡可能使用標準的請求/響應頭。以下是一些常用的標準請求頭:

字段名類型說明
Content-Typestring請求體格式,比如 application/json
Acceptstring告訴服務器可以接收的內容類型,如:application/xml, text/xml, application/json, text/javascript (for JSONP, 大多數時候都是選擇選擇application/json)
Accept-Languagestring告訴服務器可以接收的語言,如:zh-CN, en-US
Accept-Encodingstring告訴服務器可以接收的編碼,如:gzip, deflate
Accept-Charsetstring告訴服務器可以接收的字符集,如:utf-8, utf-16
Authorizationstring認證信息,取值為 Bearer token
Datestring客戶端的時間戳,最好是 UTC 時間。但服務端不能依賴這個字段,因為客戶端的時間可能不準確。

緩存相關 Header

字段名類型說明
Expiresstring告知客戶端緩存過期時間,如果與 Cache-Control 同時出現,則以 Cache-Control 為準。
Cache-Controlstring緩存控制
Last-Modifiedstring告知客戶端資源最后修改時間
If-Modified-Sincestring將 Last-Modified 的值發送給服務器,服務器判斷資源是否被修改,如果被修改,則返回 200 狀態碼,否則返回 304(Not Modified) 狀態碼
ETagstring告知客戶端資源的唯一標識
If-None-Matchstring將 ETag 的值發送給服務器,服務器判斷資源是否被修改,如果被修改,則返回 200 狀態碼,否則返回 304 狀態碼

同源策略相關 Header

字段名類型說明
Access-Control-Allow-Originstring告知客戶端可以訪問的源,如:*
Access-Control-Allow-Methodsstring告知客戶端可以訪問的方法,如:GET, POST, PUT, DELETE
Access-Control-Allow-Headersstring告知客戶端可以發送的請求頭,如果有自定義 header,則需要在這里聲明
Access-Control-Expose-Headersstring告知瀏覽器可以訪問的響應頭,默認情況下,只有 6 個基本字段可以被瀏覽器訪問:Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma
Access-Control-Max-Ageinteger指定預檢請求的結果可以緩存多久(以秒為單位)。
Access-Control-Allow-Credentialsstring告知客戶端是否可以發送 cookie,如:true

對于 POST、PUT、DELETE 等“高危”方法或者帶有自定義請求頭的方法,通常需要發送一個預檢請求(OPTIONS)進行檢查。

響應碼規范

必須使用正確的 HTTP 狀態碼。HTTP 協議定義的狀態碼分類如下:

狀態碼分類說明
1xx信息性狀態碼表示臨時響應,需要客戶端進一步操作
2xx成功狀態碼表示請求成功
3xx重定向狀態碼表示需要客戶端進一步操作
4xx客戶端錯誤狀態碼表示客戶端請求錯誤,比如 400 錯誤請求,401 未認證,403 禁止訪問,404 未找到資源,405 方法不允許,429 請求過多
5xx服務器錯誤狀態碼表示服務器處理請求錯誤,比如 500 服務器錯誤,502 網關錯誤,503 服務不可用,504 網關超時
  • 在 API 設計開發時,至少需要區分 2xx、 4xx、5xx 三種狀態碼。
  • 在必要時可以細化狀態碼
    • 創建成功:201 Created
    • 查詢成功:200 OK
    • 更新成功:200 OK,或 204 No Content,表示執行成功但不返回數據
    • 刪除成功:200 OK;未找到資源:404 Not Found,資源已被刪除或不可用 410
響應體規范
  • 對于 List 操作,返回的是資源數組;如果沒有資源,則返回空數組。
  • 對于 GET/POST/PUT,通常返回資源詳情對象
  • 對于失敗的請求,除了 HTTP 狀態碼外,需要有更詳細的錯誤信息。下面是常用字段:
字段名類型是否必填說明
codestring業務自定義的錯誤碼
messagestring用戶能讀懂的出錯信息
targetstring出錯目標對象
detailsError[]錯誤列表
helpstring幫助文檔地址

需要注意不要在 details 中異常調用棧信息,這個應該在服務日志中打印。

向后兼容規范

1. 不能減少現有參數

API 的修改或升級,必須是做加法,不能是減法。

2. 新增參數或請求數據必須有默認值

新增參數時,必須有默認值,不能是必選參數。否則會導致現有的客戶端調用失敗。

3. 不能修改原 API 的語義和簽名

已經發布的 API 有用戶在使用,因此任何對 API 的改動都不能對使用方造成負面影響。為此必須做到:

  • 新增的查詢參數不能是必選的。
  • HTTP 頭和狀態碼不能修改,可以增加,但必須有默認值。
  • 請求數據中,必選參數不能有任何修改,包括參數名、類型、值范圍(可以擴大,但不能縮小)。
  • 響應數據中,必選參數不能有任何修改,包括參數名、類型、值范圍(可以擴大,但不能縮小)。

如果做不到兼容,則需要升級 API 版本。

文檔規范

API 必須有文檔說明,最佳實踐是使用 Swagger 生成 API 文檔。內部應該有統一的 API 文檔管理平臺,對外提供 API 文檔的訪問。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/74236.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/74236.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/74236.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

QT軟件匠心開發,塑造卓越設計服務

在當今這個數字化飛速發展的時代&#xff0c;軟件已經成為我們生活中不可或缺的一部分。而QT&#xff0c;作為一款跨平臺的C圖形用戶界面應用程序開發框架&#xff0c;憑借其強大的功能和靈活性&#xff0c;在眾多軟件開發工具中脫穎而出。我們深知&#xff0c;在軟件開發領域&…

標貝科技入選2025年市級數據要素市場化配置改革“揭榜掛帥”名單

近日&#xff0c;山東省大數據局、青島市大數據局公布2025年數據要素市場化配置改革“揭榜掛帥”名單。標貝科技聯合嶗山區電子政務和大數據中心申報的“政務熱線通話錄音數據價值挖掘與權益保護”項目成功入選。這一成果不僅彰顯了標貝科技在數據領域的創新實力&#xff0c;更…

Flutter TextField 從入門到精通:掌握輸入框的完整指南

目錄 1. 引言 2. TextField 的基本用法 3. 主要屬性 4. 自定義 TextField 樣式 4.1 自定義邊框與提示文本 4.2 增加前綴/后綴圖標 4.3 只允許輸入數字 4.4 表單驗證系統 4.5 動態樣式修改 4.6 防抖搜索&#xff08;Debounce&#xff09; 5. 結論 相關推薦 1. 引言…

藍橋杯備賽 背包問題

背包問題 ![[背包問題.png]] 01背包 1.題意概要&#xff1a;有 n n n個物品和一個容量為 V V V的背包&#xff0c;每個物品有重量 w i w_i wi?和價值 v i v_i vi? 兩種屬性&#xff0c;要求選若干物品放入背包使背包中物品的總價值最大且背包中物品的總重量不超過背包的容…

MyBatis-Plus 自動填充:優雅實現創建/更新時間自動更新!

目錄 一、什么是 MyBatis-Plus 自動填充&#xff1f; &#x1f914;二、自動填充的原理 ??三、實際例子&#xff1a;創建時間和更新時間字段自動填充 ?四、注意事項 ??五、總結 &#x1f389; &#x1f31f;我的其他文章也講解的比較有趣&#x1f601;&#xff0c;如果喜歡…

arduino R4 SD卡讀寫測試

使用買來的 st7789LCD 顯示器背面就帶著一個 tf 卡槽&#xff0c;可以直接連接 tf 卡。使用 Sdfat 庫就可以實現對 sd 卡的讀寫操作。這里嘗試測試 sd 卡的讀寫功能。 LCD 顯示器的初始化 //定義LCD的對象 Adafruit_ST7789 tft Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);tf…

【武漢·4月11日】Parasoft聯合光庭信息研討會|邀您共探AI賦能新機遇

Parasoft聯合光庭信息Workshop邀您共探AI賦能新機遇 AI浪潮已至&#xff0c;你準備好了嗎&#xff1f; 在智能網聯汽車飛速發展的今天&#xff0c;AI技術正以前所未有的速度重塑行業生態。如何把握AI機遇&#xff0c;賦能企業創新&#xff1f; 4月11日&#xff0c;自動化軟件…

VLLM專題(三十九)—自動前綴緩存(二)

前綴緩存(Prefix Caching)是一種在LLM推理中廣泛使用的優化技術,旨在避免冗余的提示詞(prompt)計算。其核心思想很簡單——我們緩存已處理請求的鍵值緩存(kv-cache)塊,并在新請求的前綴與之前請求相同時重用這些塊。由于前綴緩存幾乎是一種“免費的午餐”,并且不會改變…

自動駕駛系統的車輛動力學建模:自行車模型與汽車模型的對比分析

在自動駕駛系統的車輛動力學建模中&#xff0c;自行車模型&#xff08;Bicycle Model&#xff09;和更復雜的汽車模型&#xff08;如雙軌模型或多體動力學模型&#xff09;各有其適用場景和優缺點。以下是兩者的詳細對比及選擇原因解析&#xff1a; 1. 模型定義與核心差異 特性…

C語言入門教程100講(6)類型修飾符

文章目錄 1. 什么是類型修飾符&#xff1f;2. 常見的類型修飾符3. 類型修飾符的使用3.1 short 和 long3.2 signed 和 unsigned 4. 類型修飾符的組合5. 示例代碼代碼解析&#xff1a;輸出結果&#xff1a; 6. 常見問題問題 1&#xff1a;short 和 long 的具體大小是多少&#xf…

Linux-Ubuntu 系統學習筆記 | 從入門到實戰

&#x1f4d8; Linux-Ubuntu 系統學習筆記 | 從入門到實戰 &#x1f4dc; 目錄 環境安裝基本操作Linux操作系統介紹文件系統常用命令用戶權限管理編輯器vimGCC編譯器動態庫與靜態庫Makefile 1. 環境安裝 &#x1f31f; 下載鏡像 推薦使用清華大學開源鏡像站下載Ubuntu鏡像&a…

防火墻帶寬管理

拓撲 配置 [fw]interface GigabitEthernet 0/0/0 [fw-GigabitEthernet0/0/0]service-manage all permit [fw]interface GigabitEthernet 1/0/0 [fw-GigabitEthernet1/0/0]ip address 12.0.0.1 24 [fw]interface GigabitEthernet 1/0/1 [fw-GigabitEthernet1/0/1]ip ad…

一人系統 之 為什么要做一人系統?

一人系統 之 賺錢認知篇&#xff08;下&#xff09; 本文 2119個字&#xff0c;大概閱讀時間 16分鐘。 在上一篇文章中&#xff0c;主要講了以下三個內容&#xff1a; 什么是好的工作&#xff1f;時薪高&#xff0c;并且有能力提升&#xff0c;而且最終可以獨立創業的工作&…

基于springboot的電影院管理系統(源碼+lw+部署文檔+講解),源碼可白嫖!

摘要 互聯網技術的成熟和普及&#xff0c;勢必會給人們的生活方式帶來不同程度的改變。越來越多的經營模式中都少不了線上運營&#xff0c;互聯網正強力推動著社會和經濟發展。國人對民族文化的自信和不同文化的包容&#xff0c;再加上電影行業的發展&#xff0c;如此繁榮吸引…

Java安全-類的動態加載

類的加載過程 先在方法區找class信息&#xff0c;有的話直接調用&#xff0c;沒有的話則使用類加載器加載到方法區(靜態成員放在靜態區&#xff0c;非靜態成功放在非靜態區)&#xff0c;靜態代碼塊在類加載時自動執行代碼&#xff0c;非靜態的不執行;先父類后子類&#xff0c;…

ROS多機通信功能包——Multibotnet

引言 這是之前看到一位大佬做的集群通信中間件&#xff0c;突發奇想&#xff0c;自己也來做一個&#xff0c;實現更多的功能、更清楚的架構和性能更加高效的ROS多機通信的功能包 鏈接&#xff1a;https://blog.csdn.net/benchuspx/article/details/128576723 Multibotnet Mu…

C++:背包問題習題

1. 貨幣系統 1371. 貨幣系統 - AcWing題庫 給定 V 種貨幣&#xff08;單位&#xff1a;元&#xff09;&#xff0c;每種貨幣使用的次數不限。 不同種類的貨幣&#xff0c;面值可能是相同的。 現在&#xff0c;要你用這 V 種貨幣湊出 N 元錢&#xff0c;請問共有多少種不同的…

IT工具 | node.js 進程管理工具 PM2 大升級!支持 Bun.js

P(rocess)M(anager)2 是一個 node.js 下的進程管理器&#xff0c;內置負載均衡&#xff0c;支持應用自動重啟&#xff0c;常用于生產環境運行 node.js 應用&#xff0c;非常好用&#x1f44d; &#x1f33c;概述 2025-03-15日&#xff0c;PM2發布最新版本v6.0.5&#xff0c;這…

2025年01月02日浙江鼎永前端面試

目錄 webpack 和 vite 區別react fiber 架構vue diff 算法react diff 算法hooks 源碼垂直水平布局項目介紹單點登錄大文件上傳微前端 1. webpack 和 vite 區別 Webpack 和 Vite 是兩種不同的前端構建工具&#xff0c;它們在設計理念、性能表現和使用場景上存在顯著差異。以下…

1.企業級AD活動目錄核心解析:架構、組件與集成實踐

在當今數字化時代&#xff0c;企業級網絡環境日益復雜&#xff0c;高效、安全的資源管理和用戶認證成為企業 IT 運營的關鍵。AD&#xff08;Active Directory&#xff09;活動目錄作為微軟 Windows 系列服務器中的重要目錄服務&#xff0c;為企業級網絡管理提供了強大的解決方案…