【Web動畫】CSS3 3D 行星運轉 && 瀏覽器渲染原理

来源:http://www.cnblogs.com/coco1s/archive/2016/04/28/5439619.html
-Advertisement-
Play Games

承接上一篇:【CSS3進階】酷炫的3D旋轉透視 。 最近入坑 Web 動畫,所以把自己的學習過程記錄一下分享給大家。 CSS3 3D 行星運轉 demo 頁面請戳:Demo。(建議使用Chrome打開) 本文完整的代碼,以及更多的 CSS3 效果,在我 Github 上可以看到,也希望大家可以點個 ...


承接上一篇:【CSS3進階】酷炫的3D旋轉透視 。

最近入坑 Web 動畫,所以把自己的學習過程記錄一下分享給大家。

CSS3 3D 行星運轉 demo 頁面請戳:Demo。(建議使用Chrome打開)

本文完整的代碼,以及更多的 CSS3 效果,在我 Github 上可以看到,也希望大家可以點個 star。

嗯,可能有些人打不開 demo 或者頁面亂了,貼幾張效果圖:(圖片有點大,耐心等待一會)

CSS3 3D 行星運轉效果圖

CSS3 3D 行星運轉動畫,太陽系動畫

隨機再截屏了一張:

CSS3 3D 行星運轉動畫,太陽系動畫

強烈建議你點進 Demo 頁感受一下 CSS3 3D 的魅力,圖片能展現的東西畢竟有限。

然後,這個 CSS3 3D 行星運轉動畫的製作過程不再詳細贅述,本篇的重點放在 Web 動畫介紹及性能優化方面。詳細的 CSS3 3D 可以回看上一篇博客:【CSS3進階】酷炫的3D旋轉透視。簡單的思路:

1. 利用上一篇所製作的 3D 照片牆為原型,改造而來;

2. 每一個球體的製作,想了許多方法,最終使用了這種折中的方式,每一個球體本身也是一個 CSS3 3D 圖形。然後在製作過程中使用 Sass 編寫 CSS 可以減少很多繁瑣的編寫 CSS 動畫的過程;

3. Demo 當中有使用 Javascript 寫了一個滑鼠跟隨的監聽事件,去掉這個事件,整個行星運動動畫本身是純 CSS 實現的。

 

下麵將進入本文的重點,從性能優化的角度講講瀏覽器渲染展示原理,瀏覽器的重繪與重排,動畫的性能檢測優化等:

 

   瀏覽器渲染展示原理 及 對web動畫的影響

小標題起得有點大,我們知道,不同瀏覽器的內核(渲染引擎,Rendering Engine)是不一樣的,例如現在最主流的 chrome 瀏覽器的內核是 Blink 內核(在Chrome(28及往後版本)、Opera(15及往後版本)和Yandex瀏覽器中使用),火狐是 Gecko,IE 是 Trident ,瀏覽器內核負責對網頁語法的解釋並渲染(顯示)網頁,不同瀏覽器內核的工作原理並不完全一致。

所以其實下麵將主要討論的是 chrome 瀏覽器下的渲染原理。因為 chrome 內核渲染可查證的資料較多,對於其他內核的瀏覽器不敢妄下定論,所以下麵展開的討論預設是針對 chrome 瀏覽器的。

首先,我要拋出一點結論:

使用 transform3d api 代替 transform api,強制開始 GPU 加速

這裡談到了 GPU 加速,為什麼 GPU 能夠加速 3D 變換?這一切又必須要從瀏覽器底層的渲染講起,瀏覽器渲染展示網頁的過程,老生常談,面試必問,大致分為:

1. 解析HTML(HTML Parser)

2. 構建DOM樹(DOM Tree)

3. 渲染樹構建(Render Tree)

4. 繪製渲染樹(Painting)

找到了一張很經典的圖:

瀏覽器渲染頁面過程

這個渲染過程作為一個基礎知識,繼續往下深入。

當頁面載入並解析完畢後,它在瀏覽器內代表了一個大家十分熟悉的結構:DOM(Document Object Model,文檔對象模型)。在瀏覽器渲染一個頁面時,它使用了許多沒有暴露給開發者的中間表現形式,其中最重要的結構便是(layer)。

這個層就是本文重點要討論的內容:

而在 Chrome 中,存在有不同類型的層: RenderLayer(負責 DOM 子樹),GraphicsLayer(負責 RenderLayer 的子樹)。接下來我們所討論的將是 GraphicsLayer 層。

GraphicsLayer 層是作為紋理(texture)上傳給 GPU 的。

這裡這個紋理很重要,那麼,

什麼是紋理(texture)

這裡的紋理指的是 GPU 的一個術語:可以把它想象成一個從主存儲器(例如 RAM)移動到圖像存儲器(例如 GPU 中的 VRAM)的點陣圖圖像(bitmap image)。一旦它被移動到 GPU 中,你可以將它匹配成一個網格幾何體(mesh geometry),在 Chrome 中使用紋理來從 GPU 上獲得大塊的頁面內容。通過將紋理應用到一個非常簡單的矩形網格就能很容易匹配不同的位置(position)和變形(transformation),這也就是 3D CSS 的工作原理。

說起來很難懂,直接看例子,在 chrome 中,我們是可以看到上文所述的 GraphicsLayer -- 層的概念。在開發者工具中,我們進行如下選擇調出 show layer borders 選項:

在一個極簡單的頁面,我們可以看到如下所示,這個頁面只有一個層。藍色網格表示瓦片(tile),你可以把它們當作是層的單元(並不是層),Chrome 可以將它們作為一個大層的部分上傳給 GPU:

元素自身層的創建

因為上面的頁面十分簡單,所以並沒有產生層,但是在很複雜的頁面中,譬如我們給元素設置一個 3D CSS 屬性來變換它,我們就能看到當元素擁有自己的層時是什麼樣子。

註意橘黃色的邊框,它畫出了該視圖中層的輪廓:

 

何時觸發創建層 ?

上面示意圖中黃色邊框框住的層,就是 GraphicsLayer ,它對於我們的 Web 動畫而言非常重要,通常,Chrome 會將一個層的內容在作為紋理上傳到 GPU 前先繪製(paint)進一個點陣圖中。如果內容不會改變,那麼就沒有必要重繪(repaint)層。

這樣做的意義在於:花在重繪上的時間可以用來做別的事情,例如運行 JavaScript,如果繪製的時間很長,還會造成動畫的故障與延遲。

那麼一個元素什麼時候會觸發創建一個層?從目前來說,滿足以下任意情況便會創建層:

  • 3D 或透視變換(perspective、transform) CSS 屬性
  • 使用加速視頻解碼的 <video> 元素
  • 擁有 3D (WebGL) 上下文或加速的 2D 上下文的 <canvas> 元素
  • 混合插件(如 Flash)
  • 對自己的 opacity 做 CSS 動畫或使用一個動畫變換的元素
  • 擁有加速 CSS 過濾器的元素
  • 元素有一個包含複合層的後代節點(換句話說,就是一個元素擁有一個子元素,該子元素在自己的層里)
  • 元素有一個 z-index 較低且包含一個複合層的兄弟元素(換句話說就是該元素在複合層上面渲染)

層的重繪

對於靜態 Web 頁面而言,層在第一次被繪製出來之後將不會被改變,但對於 Web 動畫,頁面的 DOM 元素是在不斷變換的,如果層的內容在變換過程中發生了改變,那麼層將會被重繪(repaint)。

強大的 chrome 開發者工具提供了工具讓我們可以查看到動畫頁面運行中,哪些內容被重新繪製了:

在舊版的 chrome 中,是有 show paint rects 這一個選項的,可以查看頁面有哪些層被重繪了,並以紅色邊框標識出來。

但是新版的 chrome 貌似把這個選項移除了,現在的選項是 enable paint flashing ,其作用也是標識出網站動態變換的地方,並且以綠色邊框標識出來。

看上面的示意圖,可以看到頁面中有幾處綠色的框,表示發生了重繪。註意 Chrome 並不會始終重繪整個層,它會嘗試智能的去重繪 DOM 中失效的部分。

按照道理,頁面發生這麼多動畫,重繪應該很頻繁才對,但是上圖我的行星動畫中我只看到了寥寥綠色重繪框,我的個人理解是,一是 GPU 優化,二是如果整個動畫頁面只有一個層,那麼運用了 transform 進行變換,頁面必然需要重繪,但是採用分層(GraphicsLayer )技術,也就是上面說符合情況的元素各自創建層,那麼一個元素所創建的層運用 transform 變換,譬如 rotate 旋轉,這個時候該層的旋轉變換並沒有影響到其他層,那麼該層不一定需要被重繪。(個人之見,還請提出指正)。

瞭解層的重繪對 Web 動畫的性能優化至關重要。

是什麼原因導致失效(invalidation)進而強制重繪的呢?這個問題很難詳盡回答,因為存在大量導致邊界失效的情況。最常見的情況就是通過操作 CSS 樣式來修改 DOM 或導致重排。

查找引發重繪和重排根源的最好辦法就是使用開發者工具的時間軸和 enable paint flashing 工具,然後試著找出恰好在重繪/重排前修改了 DOM 的地方。

總結

那麼瀏覽器是如何從 DOM 元素到最終動畫的展示呢?

  • 瀏覽器解析 HTML 獲取 DOM 後分割為多個圖層(GraphicsLayer)
  • 對每個圖層的節點計算樣式結果(Recalculate style--樣式重計算)
  • 為每個節點生成圖形和位置(Layout--迴流和重佈局)
  • 將每個節點繪製填充到圖層點陣圖中(Paint Setup和Paint--重繪)
  • 圖層作為紋理(texture)上傳至 GPU
  • 符合多個圖層到頁面上生成最終屏幕圖像(Composite Layers--圖層重組)

Web 動畫很大一部分開銷在於層的重繪,以層為基礎的複合模型對渲染性能有著深遠的影響。當不需要繪製時,複合操作的開銷可以忽略不計,因此在試著調試渲染性能問題時,首要目標就是要避免層的重繪。那麼這就給動畫的性能優化提供了方向,減少元素的重繪與迴流。

 

   迴流(reflow)與重繪(repaint)

這裡首先要分清兩個概念,重繪與迴流。

迴流(reflow)

當渲染樹(render Tree)中的一部分(或全部)因為元素的規模尺寸,佈局,隱藏等改變而需要重新構建。這就稱為迴流(reflow),也就是重新佈局(relayout)。

每個頁面至少需要一次迴流,就是在頁面第一次載入的時候。在迴流的時候,瀏覽器會使渲染樹中受到影響的部分失效,並重新構造這部分渲染樹,完成迴流後,瀏覽器會重新繪製受影響的部分到屏幕中,該過程成為重繪。

重繪(repaint)

當render tree中的一些元素需要更新屬性,而這些屬性只是影響元素的外觀,風格,而不會影響佈局的,比如 background-color 。則就叫稱為重繪。

值得註意的是,迴流必將引起重繪,而重繪不一定會引起迴流。

明顯,迴流的代價更大,簡單而言,當操作元素會使元素修改它的大小或位置,那麼就會發生迴流。

迴流何時觸發:

  • 調整視窗大小(Resizing the window)
  • 改變字體(Changing the font)
  • 增加或者移除樣式表(Adding or removing a stylesheet)
  • 內容變化,比如用戶在input框中輸入文字(Content changes, such as a user typing text in
  • an input box)
  • 激活 CSS 偽類,比如 :hover (IE 中為兄弟結點偽類的激活)(Activation of CSS pseudo classes such as :hover (in IE the activation of the pseudo class of a sibling))
  • 操作 class 屬性(Manipulating the class attribute)
  • 腳本操作 DOM(A script manipulating the DOM)
  • 計算 offsetWidth 和 offsetHeight 屬性(Calculating offsetWidth and offsetHeight)
  • 設置 style 屬性的值 (Setting a property of the style attribute)

所以對於頁面而言,我們的宗旨就是儘量減少頁面的迴流重繪,簡單的一個慄子:

// 下麵這種方式將會導致迴流reflow兩次
var newWidth = aDiv.offsetWidth + 10; // Read
aDiv.style.width = newWidth + 'px'; // Write
var newHeight = aDiv.offsetHeight + 10; // Read
aDiv.style.height = newHeight + 'px'; // Write

// 下麵這種方式更好,只會迴流reflow一次
var newWidth = aDiv.offsetWidth + 10; // Read
var newHeight = aDiv.offsetHeight + 10; // Read
aDiv.style.width = newWidth + 'px'; // Write
aDiv.style.height = newHeight + 'px'; // Write

上面四句,因為涉及了 offsetHeight 操作,瀏覽器強制 reflow 了兩次,而下麵四句合併了 offset 操作,所以減少了一次頁面的迴流。 

減少迴流、重繪其實就是需要減少對渲染樹的操作(合併多次多DOM和樣式的修改),並減少對一些style信息的請求,儘量利用好瀏覽器的優化策略。

flush隊列

其實瀏覽器自身是有優化策略的,如果每句 Javascript 都去操作 DOM 使之進行迴流重繪的話,瀏覽器可能就會受不了。所以很多瀏覽器都會優化這些操作,瀏覽器會維護 1 個隊列,把所有會引起迴流、重繪的操作放入這個隊列,等隊列中的操作到了一定的數量或者到了一定的時間間隔,瀏覽器就會 flush 隊列,進行一個批處理。這樣就會讓多次的迴流、重繪變成一次迴流重繪。

但是也有例外,因為有的時候我們需要精確獲取某些樣式信息,下麵這些:

  • offsetTop, offsetLeft, offsetWidth, offsetHeight
  • scrollTop/Left/Width/Height
  • clientTop/Left/Width/Height
  • width,height
  • 請求了getComputedStyle(), 或者 IE的 currentStyle

這個時候,瀏覽器為了反饋最精確的信息,需要立即迴流重繪一次,確保給到我們的信息是準確的,所以可能導致 flush 隊列提前執行了。

display:none 與 visibility:hidden

兩者都可以在頁面上隱藏節點。不同之處在於,

  • display:none 隱藏後的元素不占據任何空間。它的寬度、高度等各種屬性值都將“丟失”
  • visibility:hidden 隱藏的元素空間依舊存在。它仍具有高度、寬度等屬性值

從性能的角度而言,即是迴流與重繪的方面,

  • display:none  會觸發 reflow(迴流)
  • visibility:hidden  只會觸發 repaint(重繪),因為沒有發現位置變化

他們兩者在優化中 visibility:hidden 會顯得更好,因為我們不會因為它而去改變了文檔中已經定義好的顯示層次結構了。

對子元素的影響:

  • display:none 一旦父節點元素應用了 display:none,父節點及其子孫節點元素全部不可見,而且無論其子孫元素如何設置 display 值都無法顯示;
  • visibility:hidden 一旦父節點元素應用了 visibility:hidden,則其子孫後代也都會全部不可見。不過存在隱藏“失效”的情況。當其子孫元素應用了 visibility:visible,那麼這個子孫元素又會顯現出來。

 

   動畫的性能檢測及優化

耗性能樣式

不同樣式在消耗性能方面是不同的,譬如 box-shadow 從渲染角度來講十分耗性能,原因就是與其他樣式相比,它們的繪製代碼執行時間過長。這就是說,如果一個耗性能嚴重的樣式經常需要重繪,那麼你就會遇到性能問題。其次你要知道,沒有不變的事情,在今天性能很差的樣式,可能明天就被優化,並且瀏覽器之間也存在差異。

因此關鍵在於,你要藉助開發工具來分辨出性能瓶頸所在,然後設法減少瀏覽器的工作量。

好在 chrome 瀏覽器提供了許多強大的功能,讓我們可以檢測我們的動畫性能,除了上面提到的,我們還可以通過勾選下麵這個 show FPS meter 顯示頁面的 FPS 信息,以及 GPU 的使用率:

 

使用 will-change 提高頁面滾動、動畫等渲染性能

官方文檔說,這是一個仍處於實驗階段的功能,所以在未來版本的瀏覽器中該功能的語法和行為可能隨之改變。

使用方法示例:(具體每個取值的意義,去翻翻文檔)

will-change: auto
will-change: scroll-position
will-change: contents
will-change: transform        // Example of <custom-ident> 
will-change: opacity          // Example of <custom-ident>
will-change: left, top        // Example of two <animateable-feature>

will-change: unset
will-change: initial
will-change: inherit

// 示例
.example{
    will-change: transform;
}

will-change 為 web 開發者提供了一種告知瀏覽器該元素會有哪些變化的方法,這樣瀏覽器可以在元素屬性真正發生變化之前提前做好對應的優化準備工作。 這種優化可以將一部分複雜的計算工作提前準備好,使頁面的反應更為快速靈敏。

值得註意的是,用好這個屬性並不是很容易:

  • 不要將 will-change 應用到太多元素上:瀏覽器已經儘力嘗試去優化一切可以優化的東西了。有一些更強力的優化,如果與 will-change 結合在一起的話,有可能會消耗很多機器資源,如果過度使用的話,可能導致頁面響應緩慢或者消耗非常多的資源。
  • 有節制地使用:通常,當元素恢復到初始狀態時,瀏覽器會丟棄掉之前做的優化工作。但是如果直接在樣式表中顯式聲明瞭 will-change 屬性,則表示目標元素可能會經常變化,瀏覽器會將優化工作保存得比之前更久。所以最佳實踐是當元素變化之前和之後通過腳本來切換 will-change 的值。
  • 不要過早應用 will-change 優化:如果你的頁面在性能方面沒什麼問題,則不要添加 will-change 屬性來榨取一丁點的速度。 will-change 的設計初衷是作為最後的優化手段,用來嘗試解決現有的性能問題。它不應該被用來預防性能問題。過度使用 will-change 會導致大量的記憶體占用,並會導致更複雜的渲染過程,因為瀏覽器會試圖準備可能存在的變化過程。這會導致更嚴重的性能問題。
  • 給它足夠的工作時間:這個屬性是用來讓頁面開發者告知瀏覽器哪些屬性可能會變化的。然後瀏覽器可以選擇在變化發生前提前去做一些優化工作。所以給瀏覽器一點時間去真正做這些優化工作是非常重要的。使用時需要嘗試去找到一些方法提前一定時間獲知元素可能發生的變化,然後為它加上 will-change 屬性。

 

使用 transform3d api 代替 transform api,強制開始 GPU 加速

GPU 能夠加速 Web 動畫,這個上文已經反覆提到了。

3D transform 會啟用GPU加速,例如 translate3D, scaleZ 之類,當然我們的頁面可能並沒有 3D 變換,但是不代表我們不能啟用 GPU 加速,在非 3D 變換的頁面也使用 3D transform 來操作,算是一種 hack 加速法。我們實際上不需要z軸的變化,但是還是假模假樣地聲明瞭,去欺騙瀏覽器。

 

參考文獻:

Rendering: repaint, reflow/relayout, restyle

Scrolling Performance

MDN--will-change

How (not) to trigger a layout in WebKit

High Performance Animations

Accelerated Rendering in Chrome

CSS3 製作3D旋轉球體

 

到此本文結束,如果還有什麼疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

CSS3 3D 行星運轉 demo 頁面請戳:Demo。(建議使用Chrome打開)

本文完整的代碼,以及更多的 CSS3 效果,在我 Github 上可以看到,也希望大家可以點個 star。

如果本文對你有幫助,請點下推薦,寫文章不容易。

 


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

-Advertisement-
Play Games
更多相關文章
  • getElementById():獲取有指定惟一ID屬性值文檔中的元素 getElementsByName(name):返回的是數組 getElementsByTagName():返回具有指定標簽名的元素子元素集合 getAttribute():返回指定屬性名的屬性值 setAttribute(): ...
  • FKP-REST是一套前後端分離,基於javascript的全棧實現,基於node的高性能,易部署性及javascript前後端語言的一致性,學習成本,時間成本及項目快速啟動等等方面,FKP都是一種不錯的解決方案 FED: 前端有完整的腳手架系統,支持代碼的編譯、壓縮、模塊化,及基於Reactjs的 ...
  • 縮略圖組件 縮略圖在網站中最常用的就是產品列表頁面,一行顯示幾張圖片,有的在圖片底下帶有標題、描述內容、按鈕等信息。bootstrap框架將這部分獨立成一個模塊組件,通過類名.thumbnail配合bootstrap的網格系統來實現。下麵是bootstrap縮略圖組件不同版本的源碼文件: LESS ... ...
  • ...
  • 1,Bootstrap 模態對話框和簡單使用 可以使用按鈕或鏈接直接調用模態對話框,這是簡單的用法: 另外,當你需要讓對話框能夠在每次打開時表單數據清空,如下: ...
  • 最近拜讀了曾探所著的《JavaScript設計模式與開發應用》一書,在讀到發佈-訂閱模式一章時,作者不僅給出了基本模式的通用版本的發佈-訂閱模式的代碼,最後還做出了擴展,給該模式增加了離線空間功能和命名空間功能,以達到先發佈再訂閱的功能和防止名稱衝突的效果。但是令人感到遺憾的是最終代碼並沒有給出足夠 ...
  • 目前前端框架太多,接觸過angular、ember,現在開始倒騰vue 此處用到v-if、v-else、v-show,v-if或讓元素不在DOM上,v-show只是改變display:block屬性,感覺v-if好 感覺跟適合、 演示效果:http://wjf444128852.github.io/ ...
  • × 目錄 [1]水平對齊+行高 [2]水平+垂直對齊 [3]margin+垂直對齊[4]absolute[5]flex 前面的話 水平居中和垂直居中已經單獨介紹過,本文將介紹水平垂直同時居中的5種思路 思路一: text-align + line-height實現單行文本水平垂直居中 思路二: te ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...