vue從入門到進階:Vuex狀態管理(十)

来源:https://www.cnblogs.com/moqiutao/archive/2018/01/23/8336824.html
-Advertisement-
Play Games

Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式。它採用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。 在 Vue 之後引入 vuex 會進行自動安裝: 可以通過 https://unpkg.com/[email protected] 這樣的方式指定特定的版本 ...


Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式。它採用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。

在 Vue 之後引入 vuex 會進行自動安裝:

<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>

可以通過 https://unpkg.com/[email protected] 這樣的方式指定特定的版本。

NPM

npm install vuex --save

State

在 Vue 組件中獲得 Vuex 狀態

const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return this.$store.state.count
    }
  }
}

mapState 輔助函數

當一個組件需要獲取多個狀態時候,將這些狀態都聲明為計算屬性會有些重覆和冗餘。為瞭解決這個問題,我們可以使用 mapState 輔助函數幫助我們生成計算屬性,讓你少按幾次鍵:

// 在單獨構建的版本中輔助函數為 Vuex.mapState
import { mapState } from 'vuex'

export default {
  // ...
  computed: mapState({
    // 箭頭函數可使代碼更簡練
    count: state => state.count,

    // 傳字元串參數 'count' 等同於 `state => state.count`
    countAlias: 'count',

    // 為了能夠使用 `this` 獲取局部狀態,必須使用常規函數
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
  })
}

當映射的計算屬性的名稱與 state 的子節點名稱相同時,我們也可以給 mapState 傳一個字元串數組。

computed: mapState([
  // 映射 this.count 為 store.state.count
  'count'
])

對象展開運算符

mapState 函數返回的是一個對象。我們如何將它與局部計算屬性混合使用呢?通常,我們需要使用一個工具函數將多個對象合併為一個,以使我們可以將最終對象傳給 computed 屬性。

computed: {
  localComputed () { /* ... */ },
  // 使用對象展開運算符將此對象混入到外部對象中
  ...mapState({
    // ...
  })
}

Getter

有時候我們需要從 store 中的 state 中派生出一些狀態,例如對列表進行過濾並計數:

computed: {
  doneTodosCount () {
    return this.$store.state.todos.filter(todo => todo.done).length
  }
}

如果有多個組件需要用到此屬性,我們要麼複製這個函數,或者抽取到一個共用函數然後在多處導入它——無論哪種方式都不是很理想。

Vuex 允許我們在 store 中定義“getter”(可以認為是 store 的計算屬性)。就像計算屬性一樣,getter 的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變才會被重新計算。

Getter 接受 state 作為其第一個參數:

const store = new Vuex.Store({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    doneTodos: state => {
      return state.todos.filter(todo => todo.done)
    }
  }
})

Getter 會暴露為 store.getters 對象:

store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]

Getter 也可以接受其他 getter 作為第二個參數:

getters: {
  // ...
  doneTodosCount: (state, getters) => {
    return getters.doneTodos.length
  }
}

store.getters.doneTodosCount // -> 1

我們可以很容易地在任何組件中使用它:

computed: {
  doneTodosCount () {
    return this.$store.getters.doneTodosCount
  }
}

你也可以通過讓 getter 返回一個函數,來實現給 getter 傳參。在你對 store 里的數組進行查詢時非常有用。

getters: {
  // ...
  getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }
}

store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }

mapGetters 輔助函數

mapGetters 輔助函數僅僅是將 store 中的 getter 映射到局部計算屬性:

import { mapGetters } from 'vuex'

export default {
  // ...
  computed: {
  // 使用對象展開運算符將 getter 混入 computed 對象中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
  }
}

如果你想將一個 getter 屬性另取一個名字,使用對象形式:

mapGetters({
  // 映射 `this.doneCount` 為 `store.getters.doneTodosCount`
  doneCount: 'doneTodosCount'
})

 

Mutation

更改 Vuex 的 store 中的狀態的唯一方法是提交 mutation。Vuex 中的 mutation 非常類似於事件:每個 mutation 都有一個字元串的 事件類型 (type) 和 一個 回調函數 (handler)。這個回調函數就是我們實際進行狀態更改的地方,並且它會接受 state 作為第一個參數:

const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 變更狀態
      state.count++
    }
  }
})
store.commit('increment')

當使用對象風格的提交方式,整個對象都作為載荷傳給 mutation 函數,因此 handler 保持不變:

mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}

使用常量替代 Mutation 事件類型

// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'

// store.js
import Vuex from 'vuex'
import { SOME_MUTATION } from './mutation-types'

const store = new Vuex.Store({
  state: { ... },
  mutations: {
    // 我們可以使用 ES2015 風格的計算屬性命名功能來使用一個常量作為函數名
    [SOME_MUTATION] (state) {
      // mutate state
    }
  }
})

在組件中提交 Mutation

你可以在組件中使用 this.$store.commit('xxx') 提交 mutation,或者使用 mapMutations 輔助函數將組件中的 methods 映射為 store.commit 調用(需要在根節點註入 store)。

import { mapMutations } from 'vuex'

export default {
  // ...
  methods: {
    ...mapMutations([
      'increment', // 將 `this.increment()` 映射為 `this.$store.commit('increment')`

      // `mapMutations` 也支持載荷:
      'incrementBy' // 將 `this.incrementBy(amount)` 映射為 `this.$store.commit('incrementBy', amount)`
    ]),
    ...mapMutations({
      add: 'increment' // 將 `this.add()` 映射為 `this.$store.commit('increment')`
    })
  }
}

Action

Action 類似於 mutation,不同在於:

  • Action 提交的是 mutation,而不是直接變更狀態。
  • Action 可以包含任意非同步操作。

讓我們來註冊一個簡單的 action:

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

Action 函數接受一個與 store 實例具有相同方法和屬性的 context 對象,因此你可以調用 context.commit 提交一個 mutation,或者通過 context.statecontext.getters 來獲取 state 和 getters。

實踐中,我們會經常用到 ES2015 的 參數解構 來簡化代碼(特別是我們需要調用 commit 很多次的時候):

actions: {
  increment ({ commit }) {
    commit('increment')
  }
}

分發 Action

Action 通過 store.dispatch 方法觸發:

store.dispatch('increment')

乍一眼看上去感覺多此一舉,我們直接分發 mutation 豈不更方便?實際上並非如此,還記得 mutation 必須同步執行這個限制麽?Action 就不受約束!我們可以在 action 內部執行非同步操作:

actions: {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}

Actions 支持同樣的載荷方式和對象方式進行分發:

// 以載荷形式分發
store.dispatch('incrementAsync', {
  amount: 10
})

// 以對象形式分發
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})

來看一個更加實際的購物車示例,涉及到調用非同步 API分發多重 mutation

actions: {
  checkout ({ commit, state }, products) {
    // 把當前購物車的物品備份起來
    const savedCartItems = [...state.cart.added]
    // 發出結賬請求,然後樂觀地清空購物車
    commit(types.CHECKOUT_REQUEST)
    // 購物 API 接受一個成功回調和一個失敗回調
    shop.buyProducts(
      products,
      // 成功操作
      () => commit(types.CHECKOUT_SUCCESS),
      // 失敗操作
      () => commit(types.CHECKOUT_FAILURE, savedCartItems)
    )
  }
}

在組件中分發 Action

你在組件中使用 this.$store.dispatch('xxx') 分發 action,或者使用 mapActions 輔助函數將組件的 methods 映射為 store.dispatch 調用(需要先在根節點註入 store):

import { mapActions } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions([
      'increment', // 將 `this.increment()` 映射為 `this.$store.dispatch('increment')`

      // `mapActions` 也支持載荷:
      'incrementBy' // 將 `this.incrementBy(amount)` 映射為 `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // 將 `this.add()` 映射為 `this.$store.dispatch('increment')`
    })
  }
}

Module

由於使用單一狀態樹,應用的所有狀態會集中到一個比較大的對象。當應用變得非常複雜時,store 對象就有可能變得相當臃腫。

為瞭解決以上問題,Vuex 允許我們將 store 分割成模塊(module)。每個模塊擁有自己的 state、mutation、action、getter、甚至是嵌套子模塊——從上至下進行同樣方式的分割:

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的狀態
store.state.b // -> moduleB 的狀態

一般項目結構

Vuex 並不限制你的代碼結構。但是,它規定了一些需要遵守的規則:

  1. 應用層級的狀態應該集中到單個 store 對象中。

  2. 提交 mutation 是更改狀態的唯一方法,並且這個過程是同步的。

  3. 非同步邏輯都應該封裝到 action 裡面。

只要你遵守以上規則,如何組織代碼隨你便。如果你的 store 文件太大,只需將 action、mutation 和 getter 分割到單獨的文件。

對於大型應用,我們會希望把 Vuex 相關代碼分割到模塊中。下麵是項目結構示例:

├── index.html
├── main.js
├── api
│   └── ... # 抽取出API請求
├── components
│   ├── App.vue
│   └── ...
└── store
    ├── index.js          # 我們組裝模塊並導出 store 的地方
    ├── actions.js        # 根級別的 action
    ├── mutations.js      # 根級別的 mutation
    └── modules
        ├── cart.js       # 購物車模塊
        └── products.js   # 產品模塊

請參考購物車示例

 總結

安裝vuex

npm install --save vuex
<!--這裡假定你已經搭好vue的開發環境了--> 

配置vuex

1、首先創建一個js文件,假定這裡取名為store.js
2、在main.js文件中引入上面創建的store.js

//main.js內部對store.js的配置
import store from '"@/store/store.js' 
//具體地址具體路徑
new Vue({
    el: '#app',
    store, //將store暴露出來
    template: '<App></App>',
    components: { App }
});

store.js中的配置

import Vue from 'vue'; //首先引入vue
import Vuex from 'vuex'; //引入vuex
Vue.use(Vuex) 

export default new Vuex.Store({
    state: { 
        // state 類似 data
        //這裡面寫入數據
    },
    getters:{ 
        // getters 類似 computed 
        // 在這裡面寫個方法
    },
    mutations:{ 
        // mutations 類似methods
        // 寫方法對數據做出更改(同步操作)
    },
    actions:{
        // actions 類似methods
        // 寫方法對數據做出更改(非同步操作)
    }
})

使用vuex

我們約定store中的數據是以下形式

state:{
    goods: {
        totalPrice: 0,
        totalNum:0,
        goodsData: [
            {
                id: '1',
                title: '好吃的蘋果',
                price: 8.00,
                image: 'https://www.shangdian.com/static/pingguo.jpg',
                num: 0
            },
            {
                id: '2',
                title: '美味的香蕉',
                price: 5.00,
                image: 'https://www.shangdian.com/static/xiangjiao.jpg',
                num: 0
            }
        ]
    }
},
gettles:{ //其實這裡寫上這個主要是為了讓大家明白他是怎麼用的,
    totalNum(state){
        let aTotalNum = 0;
        state.goods.goodsData.forEach((value,index) => {
            aTotalNum += value.num;
        })
        return aTotalNum;
     },
     totalPrice(state){
        let aTotalPrice = 0;
        state.goods.goodsData.forEach( (value,index) => {
            aTotalPrice += value.num * value.price
         })
         return aTotalPrice.toFixed(2);
    }
},
mutations:{
    reselt(state,msg){
        console.log(msg) //我執行了一次;
        state.goods.totalPrice = this.getters.totalPrice;
        state.goods.totalNum = this.getters.totalNum;
    },
    reduceGoods(state,index){ 
        //第一個參數為預設參數,即上面的state,後面的參數為頁面操作傳過來的參數
        state.goodsData[index].num-=1;
        
        let msg = '我執行了一次'
        this.commit('reselt',msg);
    },
    addGoods(state,index){
        state.goodsData[index].num+=1;
        
        let msg = '我執行了一次'
        this.commit('reselt',msg);
        /**
            想要重新渲染store中的方法,一律使用commit 方法 
            你可以這樣寫 commit('reselt',{
                state: state
            })
            也可以這樣寫 commit({
                type: 'reselt',
                state: state 
            })
            主要看你自己的風格
        **/
    }
},
actions:{
    //這裡主要是操作非同步操作的,使用起來幾乎和mutations方法一模一樣
    //除了一個是同步操作,一個是非同步操作,這裡就不多介紹了,
    //有興趣的可以自己去試一試
    //比如你可以用setTimeout去嘗試一下
}

好了,簡單的數據我們就這樣配置了,接下來看看購物車頁面吧;

第一種方式使用store.js中的數據(直接使用)

<template>
    <div id="goods" class="goods-box">
        <ul class="goods-body">
            <li v-for="(list,index) in goods.goodsData" :key="list.id">
                <div class="goods-main">
                    <img :src="list.image">
                </div>
                <div class="goods-info">
                    <h3 class="goods-title">{{ list.title }}</h3>
                    <p class="goods-price">¥ {{ list.price }}</p>
                    <div class="goods-compute">
                        <!--在dom中使用方法為:$store.commit()加上store.js中的屬性的名稱,示例如下-->
                        <span class="goods-reduce" @click="$store.commit('reduceGoods',index)">-</span>
                        <input readonly v-model="list.num" />
                        <span class="goods-add" @click="$store.commit('addGoods',index)">+</span>
                    </div>
                </div>
            </li>
        </ul>
        <div class="goods-footer">
            <div class="goods-total">
                合計:¥ {{ goods.totalPrice }}
                <!--
                    如果你想要直接使用一些數據,但是在computed中沒有給出來怎麼辦?
                    可以寫成這樣
                    {{ $store.state.goods.totalPrice }}
                    或者直接獲取gettles裡面的數據
                    {{ $store.gettles.totalPrice }}
                -->
            </div>
            <button class="goods-check" :class="{activeChecke: goods.totalNum <= 0}">去結賬({{ goods.totalNum }})</button>
        </div>
    </div>
</template>
<script>
    export default {
        name: 'Goods',
        computed:{
            goods(){
                return this.$store.state.goods;
            }
        }
    }
</script>

如果上面的方式寫參數讓你看的很彆扭,我們繼續看第二種方式

第一種方式使用store.js中的數據(通過輔助函數使用)

<!--goods.vue 購物車頁面-->
<template>
    <div id="goods" class="goods-box">
        <ul class="goods-body">
            <li v-for="(list,index) in goods.goodsData" :key="list.id">
                <div class="goods-main">
                    <img :src="list.image">
                </div>
                <div class="goods-info">
                    <h3 class="goods-title">{{ list.title }}</h3>
                    <p class="goods-price">¥ {{ list.price }}</p>
                    <div class="goods-compute">
                        <span class="goods-reduce" @click="goodsReduce(index)">-</span>
                        <input readonly v-model="list.num" />
                        <span class="goods-add" @click="goodsAdd(index)">+</span>
                    </div>
                </div>
            </li>
        </ul>
        <div class="goods-footer">
            <div class="goods-total">
                合計:¥ {{ goods.totalPrice }}
                <!--
                    gettles裡面的數據可以直接這樣寫
                    {{ totalPrice }}
                -->
            </div>
            <button class="goods-check" :class="{activeChecke: goods.totalNum <= 0}">去結賬({{ goods.totalNum }})</button>
        </div>
    </div>
</template>
<script>
    import {mapState,mapGetters,mapMutations} from 'vuex';
    /**
        上面大括弧裡面的三個參數,便是一一對應著store.js中的state,gettles,mutations
        這三個參數必須規定這樣寫,寫成其他的單詞無效,切記
        畢竟是這三個屬性的的輔助函數
    **/
    
    export default {
        name: 'Goods',
        computed:{
            ...mapState(['goods']) 
            ...mapGetters(['totalPrice','totalNum'])
            /**
                ‘...’ 為ES6中的擴展運算符,不清楚的可以百度查一下
                如果使用的名稱和store.js中的一樣,直接寫成上面數組的形式就行,
                如果你想改變一下名字,寫法如下
                ...mapState({
                    goodsData: state => stata.goods
                })
                
            **/
        },
        methods:{
            ...mapMutations(['goodsReduce','goodsAdd']),
            /**
                這裡你可以直接理解為如下形式,相當於直接調用了store.js中的方法
                goodsReduce(index){
                    // 這樣是不是覺得很熟悉了?
                },
                goodsAdd(index){
                    
                }
                好,還是不熟悉,我們換下麵這種寫法
                
                onReduce(index){ 
                    //我們在methods中定義了onReduce方法,相應的Dom中的click事件名要改成onReduce
                    this.goodsReduce(index)
                    //這相當於調用了store.js的方法,這樣是不是覺得滿意了
                }
                
            **/
        }
    }
</script>

Module

const moduleA = {
  state: { /*data**/ },
  mutations: { /**方法**/ },
  actions: { /**方法**/ },
  getters: { /**方法**/ }
}

const moduleB = {
  state: { /*data**/ },
  mutations: { /**方法**/ },
  actions: { /**方法**/ }
}

export default new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

//那怎麼調用呢?看下麵!

//在模塊內部使用
state.goods //這種使用方式和單個使用方式樣,直接使用就行

//在組件中使用
store.state.a.goods //先找到模塊的名字,再去調用屬性
store.state.b.goods //先找到模塊的名字,再去調用屬性

參考地址:《震驚!喝個茶的時間就學會了vuex》


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

-Advertisement-
Play Games
更多相關文章
  • 介紹HTTP緩存之前先簡單說一下Web緩存 Web緩存是一種保存Web資源副本併在下次請求時直接使用該副本的技術。        Web緩存可以分為這幾種:瀏覽器緩存、CDN緩存、伺服器緩存、資料庫數據緩存 。因為可能會直接使用副 ...
  • 本文設計到常見對文檔的處理樣式,和塊,行標簽的特點。 沒用什麼重要內容,只是自己的一些知識點的回憶,對以前知識的一個梳理過程,望某懶蟲加油!!! ...
  • classList屬性的方法:add();remove();toggle(); 描述,在一些頁面我們需要使用兩個按鈕來回切換,如圖: 我們要使用到add()和remove()方法 html部分: <div class="login-title"> <a href="javascript:void(0 ...
  • 2017年npm上最熱門的項目之一——Pkg,可以直接將node.js項目打包成windows可以直接執行的exe文件(也支持FreeBSD、linux、macos、arm系統),並且無須修改你項目中的任何代碼。本文對該項目作了簡要說明與教程,並提供了一個簡單示例來說明其使用場景。 ...
  • CreateJS介紹請看CreateJS中文網或者官方網站 一.使用EaselJS 先到官網下載easeljs,也可以點這裡 1.得到easeljs-0.8.1.min.js後,新建一個HTML5文件並導入: 2.入口函數和創建canvas標簽: 3.創建舞臺: 二.使用EaselJS創建圖形和文字 ...
  • css代碼: html代碼: JS調用: ...
  • jquery的綠色拖動驗證功能 在網上看到了一個這樣的問題:那種像拖動滑塊匹配圖形的驗證方式是怎麼實現的?。 突然想到實現一個簡單綠色拖動驗證碼的功能,在網上搜了下,有一個用jquery實現的該功能代碼。 體驗地址:http://yanshi.sucaihuo.com/jquery/8/897/de ...
  • 最近在做的一個後臺管理系統,發現一個bug: 問題描述:如果其他列表項都用類為col-xs-12的div包裹,而引入UEditor的部分不用類為col-xs-12的div包裹,那麼其他列表項將無法顯示,UEditor編輯框也顯示不完全; 解決辦法:將引入UEditor的部分也用類為col-xs-12 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...