DjangoRestFramework,認證組件、許可權組件、頻率組件、url註冊器、響應器、分頁組件

来源:https://www.cnblogs.com/changxin7/archive/2019/12/16/12047440.html
-Advertisement-
Play Games

一 認證組件 1. 局部認證組件 我們知道,我們不管路由怎麼寫的,對應的視圖類怎麼寫的,都會走到dispatch方法,進行分發, 在咱們看的APIView類中的dispatch方法的源碼中,有個self.initial(request, args, kwargs),那麼認證、許可權、頻率這三個預設組件 ...


一 認證組件

  1. 局部認證組件

    我們知道,我們不管路由怎麼寫的,對應的視圖類怎麼寫的,都會走到dispatch方法,進行分發,

    在咱們看的APIView類中的dispatch方法的源碼中,有個self.initial(request, *args, **kwargs),那麼認證、許可權、頻率這三個預設組件都在這個方法裡面了,如果我們自己沒有做這三個組件的配置,那麼會使用源碼中預設的一些配置。進源碼去看看你就會看到下麵三個東西:

# Ensure that the incoming request is permitted
#實現認證
self.perform_authentication(request)
#許可權判斷
self.check_permissions(request)
#控制訪問頻率
elf.check_throttles(request)

    目前為止大家知道的認證機制是不是有cookie、session啊,session更安全一些,但是你會發現session的信息都存到咱們的伺服器上了,如果用戶量很大的話,伺服器壓力是比較大的,並且django的session存到了django_session表中,不是很好操作,但是一般的場景都是沒有啥問題的,現在生產中使用的一個叫做token機制的方式比較多,現在我們是不是就知道個csrf_token啊,其實token有很多種寫法,如何加密,你是hashlib啊還是base64啊還是hmac啊等,是不是加上過期時間啊,是不是要加上一個secret_key(客戶端與服務端協商好的一個字元串,作為雙方的認證依據),是不是要持續刷新啊(有效時間要短,不斷的更新token,如果在這麼短的時間內還是被別人拿走了token,模擬了用戶狀態,那這個基本是沒有辦法的,但是你可以在網路或者網路設備中加安全,存客戶的ip地址等,防黑客)等等。

    大致流程圖解:

      img

    

    首先我們需要創建一個表,用戶表,裡面放一個token欄位,其實一般我都是放到兩個表裡面,和用戶表是一個一對一關係的表,看代碼:

################################# user表 ###############################
class User(models.Model):
    user = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
    type_choice=((1,"VIP"),(2,"SVIP"),(3,"SSVIP"))
    user_type = models.IntegerField(choices=type_choice)

class UserToken(models.Model):
    user = models.OneToOneField(to=User) #一對一到用戶表
    token = models.CharField(max_length=128) #設置的長度大一些
    # expire_time = models.DateTimeField() #如果做超時時間限制,可以在這裡加個欄位來搞,這裡我沒有寫昂,簡單搞了

    urls.py內容如下:

#登陸認證介面
url(r'^login/$', views.LoginView.as_view(),), #別忘了$符號結尾

    views.py內容如下:自己寫一個每次登陸成功之後刷新token值

###################login邏輯介面#######################
#關於邏輯介面而不是提供數據的介面,我們不用ModelViewSet,而是直接寫個類,繼承APIView,然後在類裡面直接寫咱的邏輯
import uuid
import os
import json
class LoginView(APIView):
    #從前後端分離的項目來講,get請求不需要寫,因為get就是個要登陸頁面的操作,vue就搞定了,所以我們這裡直接寫post請求就可以了
    def post(self,request):
        # 一般,請求過來之後,我們後端做出的響應,都是個字典,不僅包含錯誤信息,還有要狀態碼等,讓客戶端明白到底發生了什麼事情
        # 'code'的值,1表示成功,0表示失敗,2表示其他錯誤(自己可以做更細緻的錯誤代碼昂)
        res = {'code': 1, 'msg': None, 'user': None,'token':None}
        print(request.data)
        try:
            user = request.data.get('user')
            pwd = request.data.get('pwd')
            # 資料庫中查詢
            user_obj = models.User.objects.filter(user=user, pwd=pwd).first()
            if user_obj:
                res['user'] = user_obj.user
                # 添加token,用到咱們usertoken表
                # models.UserToken.objects.create(user=user,token='123456')
                # 創建token隨機字元串,我寫了兩個方式,簡寫的昂,最好再加密一下
                random_str = uuid.uuid4()
                # random_str = os.urandom(16) bytes類型的16位的隨機字元串
                models.UserToken.objects.update_or_create(
                    user=user_obj,  # 查找篩選條件
                    defaults={  # 添加或者更新的數據
                        "token": random_str,
                    }
                )
                res['token'] = random_str
                res['msg'] = '登陸成功'
            else:
                res['code'] = 0
                res['msg'] = '用戶名或者密碼錯誤'
                return Response(res)
        except Exception as e:
            res['code'] = 2
            res['msg'] = str(e)

        return Response(res)

    通過上面的代碼我們將token返回給了用戶,那麼以後用戶不管發送什麼請求,都要帶著我給它的token值來訪問,認證token通過才行,並且更新token。

    下麵我們玩一下drf提供的認證組件的玩法。

  DRF的認證組件

    將來有些數據介面是必須要求用戶登陸之後才能獲取到數據,所以將來用戶登陸完成之後,每次再過來請求,都要帶著token來,作為身份認證的依據。

from app01.serializer import BookSerializers

#####################Book表操作##########################

class UserAuth():
   def authenticate_header(self,request):
         pass
#authenticate方法固定的,並且必須有個參數,這個參數是新的request對象,不信,看源碼
    def authenticate(self,request):

        if 1:
        #源碼中會發現,這個方法會有兩個返回值,並且這兩個返回值封裝到了新的request對象中了,request.user-->用戶名 和 request.auth-->token值,這兩個值作為認證結束後的返回結果
            return "chao","asdfasdfasdf"

class BookView(APIView):
    #認證組件肯定是在get、post等方法執行之前執行的,還記得源碼的地方嗎,這個組件是在dispatch的地方調用的,我們是上面寫個UserAuth類
    authentication_classes = [UserAuth,] #認證類可以寫多個,一個一個的順序驗證
    def get(self,request):
        '''
        查看所有書籍
        :param request:
        :return:
        '''
        #這樣就拿到了上面UserAuth類的authenticate方法的兩個返回值
        print(request.user)  
        print(request.auth)
        book_obj_list = models.Book.objects.all()
        s_books = BookSerializers(book_obj_list,many=True)
        return Response(s_books.data)
    def _authenticate(self):
        """
        Attempt to authenticate the request using each authentication instance
        in turn.
        """
        for authenticator in self.authenticators:
            try:
                user_auth_tuple = authenticator.authenticate(self) 
            except exceptions.APIException:
                self._not_authenticated()
                raise

            if user_auth_tuple is not None:
                self._authenticator = authenticator
                #值得註意的是,self是APIView封裝的新的request對象
                self.user, self.auth = user_auth_tuple 
                return   #退出了這個函數,函數就不會執行了,不會再迴圈了,所以如果你的第一個認證類有返回值,那麼第二個認證類就不會執行了,所以別忘了return是結束函數的意思,所以如果你有多個認證類,那麼返回值放到最後一個類裡面

  好,我們寫一寫獲取token值,然後校驗的功能,看views.py的代碼:

from django.shortcuts import render,HttpResponse,redirect
from django.views import View
from rest_framework import serializers
from app01 import models
from rest_framework.views import APIView
from rest_framework.response import Response
#將序列化組件都放到一個單獨的文件裡面,然後引入進來
from app01.serializer import BookSerializers,PublishSerializers,AuthorSerializers
#drf提供的認證失敗的異常
from rest_framework.exceptions import AuthenticationFailed

class UserAuth():
    #每個認證類,都需要有個authenticate_header方法,並且有個參數request
    def authenticate_header(self,request):
        pass
    #authenticate方法固定的,並且必須有個參數,這個參數是新的request對象,不信,看源碼
    def authenticate(self,request):
        # token = request._request.GET.get("token")
        #由於我們這個request是新的request對象,並且老的request對象被封裝到了新的request對象中,名字是self._request,所以上面的取值方式是沒有問題的,不過人家APIView不僅封裝了老的request對象,並且還給你加了query_params屬性,和老的request.GET得到的內容是一樣的,所以可以直接按照下麵的方式來寫
        token = request.query_params.get("token")
        #用戶請求來了之後,我們獲取token值,到資料庫中驗證
        usertoken = models.UserToken.objects.filter(token=token).first()
        if usertoken:
            #驗證成功之後,可以返回兩個值,也可以什麼都不返回
            return usertoken.user.user,usertoken.token

        #源碼中會發現,這個方法會有兩個返回值,並且這兩個返回值封裝到了新的request對象中了,request.user-->用戶名 和 request.auth-->token值,這兩個值作為認證結束後的返回結果
        else:
            #因為源碼內部進行了異常捕獲,並且給你主動返回一個forbiden錯誤,所以我們在這裡主動拋出異常就可以了
            raise AuthenticationFailed("認證失敗")

    urls.py內容如下:

url(r'^books/$', views.BookView.as_view(),),

    通過postman發送請求,你會發現錯誤:

      img

    如果我們請求中帶了資料庫中保存的token值,那麼就會成功獲取數據,看資料庫中的token值:

      img

    然後通過postman再請求,帶著token值,看效果,成功了:

      img

    

    繼承drf的BaseAuthentication認證類的寫法:

from app01 import models
from rest_framework.views import APIView
from rest_framework.response import Response
#將序列化組件都放到一個單獨的文件裡面,然後引入進來
from app01.serializer import BookSerializers,PublishSerializers,AuthorSerializers
#drf提供的認證失敗的異常
from rest_framework.exceptions import AuthenticationFailed
from rest_framework.authentication import BaseAuthentication
#繼承drf的BaseAuthentication類
class UserAuth(BaseAuthentication):
    # 繼承了BaseAuthentication類之後,這個方法就不用寫了
    # def authenticate_header(self,request):
    #     pass
    def authenticate(self,request):
        # token = request._request.GET.get("token")
        token = request.query_params.get("token")
        #有request對象,那麼不僅僅可以認證token,還可以認證請求裡面的其他內容
        usertoken = models.UserToken.objects.filter(token=token).first()
        if usertoken:
            #驗證成功之後
            return usertoken.user.user,usertoken.token
        else:
            raise AuthenticationFailed("認證失敗")

class BookView(APIView):
    #通過源碼看,認證類的查找過程,和解析組件的查找過程是一樣的
    authentication_classes = [UserAuth,]
    def get(self,request):
        '''
        查看所有書籍
        :param request:
        :return:
        '''
        print(request.user)
        print(request.auth)
        book_obj_list = models.Book.objects.all()
        s_books = BookSerializers(book_obj_list,many=True)
        return Response(s_books.data)

    帶時間戳的隨機字元串:

def get_random_str(user):
    import hashlib,time
    ctime=str(time.time())

    md5=hashlib.md5(bytes(user,encoding="utf8"))
    md5.update(bytes(ctime,encoding="utf8"))

    return md5.hexdigest()

  全局視圖認證組件:

    在settings.py文件中配置:如果我再app01文件夾下的service文件夾下的auth文件夾下寫了我們自己的認證類,那麼全局配置的寫法就按照下麵的方式寫。

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",]  #裡面是路徑字元串
}

  認證組件就說這些,看許可權組件吧。

二 許可權組件

  局部視圖許可權:

    在app01.service.permissions.py中

from rest_framework.permissions import BasePermission
class SVIPPermission(BasePermission):
    message="SVIP才能訪問!" #變數只能叫做message
    def has_permission(self, request, view):  #重寫has_permission方法,自己寫許可權邏輯,看看源碼就明白了,這個view是咱當前類的實例化對象,一般用不到,但是必須給個參數寫在這裡。
        if request.user.user_type==3:
            return True  #通過許可權
        return False     #沒有通過

    在views.py:

from app01.service.permissions import *

class BookViewSet(generics.ListCreateAPIView):
    permission_classes = [SVIPPermission,]
    queryset = Book.objects.all()
    serializer_class = BookSerializers

  全局視圖許可權:

    settings.py配置如下:

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",]
}

三 頻率組件

局部視圖throttle,反爬,防攻擊

在throttles.py中:

from rest_framework.throttling import BaseThrottle,SimpleRateThrottle
import time
from rest_framework import exceptions
visit_record = {}
class VisitThrottle(BaseThrottle):
    # 限制訪問時間
    VISIT_TIME = 10
    VISIT_COUNT = 3

    # 定義方法 方法名和參數不能變
    def allow_request(self, request, view):
        # 獲取登錄主機的id
        id = request.META.get('REMOTE_ADDR')
        self.now = time.time()

        if id not in visit_record:
            visit_record[id] = []

        self.history = visit_record[id]
        # 限制訪問時間
        while self.history and self.now - self.history[-1] > self.VISIT_TIME:
            self.history.pop()
        # 此時 history中只保存了最近10秒鐘的訪問記錄
        if len(self.history) >= self.VISIT_COUNT:
            return False
        else:
            self.history.insert(0, self.now)
            return True

    def wait(self):
        return self.history[-1] + self.VISIT_TIME - self.now

在views.py中:

from app01.service.throttles import *

class BookViewSet(generics.ListCreateAPIView):
    throttle_classes = [VisitThrottle,]
    queryset = Book.objects.all()
    serializer_class = BookSerializers

全局視圖throttle

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
    "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",]
}

內置throttle類

在throttles.py修改為:

class VisitThrottle(SimpleRateThrottle):

    scope="visit_rate"
    def get_cache_key(self, request, view):

        return self.get_ident(request)

  settings.py設置:

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
    "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",],
    "DEFAULT_THROTTLE_RATES":{
        "visit_rate":"5/m",
    }
}

四 url註冊器

幫我們自動生成4個url,和我們自己寫的差不多:

from django.conf.urls import url,include
from django.contrib import admin
from app01 import views
from rest_framework import routers

router = routers.DefaultRouter()
#自動幫我們生成四個url
router.register(r'authors', views.AuthorView)
router.register(r'books', views.BookView)


urlpatterns = [

    # url(r'^books/$', views.BookView.as_view(),), #別忘了$符號結尾
    # url(r'api/', include(router.urls)),
    url(r'', include(router.urls)),   #http://127.0.0.1:8000/books/  也可以這樣寫:http://1270.0..1:8000/books.json/
   
    #登陸認證介面
    url(r'^login/$', views.LoginView.as_view(),), #別忘了$符號結尾

]

但是有個前提就是,我們用的是:ModelViewSet序列化組件。

from rest_framework.viewsets import ModelViewSet
class AuthorView(ModelViewSet):
    queryset = models.Author.objects.all() 
    serializer_class = AuthorSerializers

class BookView(ModelViewSet):
    queryset = models.Book.objects.all()
    serializer_class = BookSerializers

所以,這個url註冊器其實並沒有那麼好用,當然啦,看需求.

五 響應器

簡單看看就行啦:

from rest_framework.viewsets import ModelViewSet
from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
#如果我們沒有在自己的視圖類裡面配置,那麼源碼裡面預設就用的這兩個JSONRenderer,BrowsableAPIRenderer
#BrowsableAPIRenderer 是當客戶端為瀏覽器的時候,回覆的數據會自動給你生成一個頁面形式的數據展示,一般開發的時候,都不用頁面形式的
#JSONRenderer:回覆的是json數據

class BookView(ModelViewSet):
    # renderer_classes = [JSONRenderer,] #其實預設就是這個JSONRenderer,所以一般不用在這裡配置了
    queryset = models.Book.objects.all()
    serializer_class = BookSerializers

六 分頁器組件

簡單使用:

#引入分頁
from rest_framework.pagination import PageNumberPagination
class BookView(APIView):
    # 通過源碼看,認證類的查找過程,和解析組件的查找過程是一樣的
    # authentication_classes = [UserAuth,]
    # throttle_classes = [VisitThrottle,]

    def get(self,request):
        '''
        查看所有書籍
        :param request:
        :return:
        '''
        
        book_obj_list = models.Book.objects.all()
        #創建分頁器對象,PageNumberPagination類中除了PAGE_SIZE屬性之外,還有個page屬性,這個page屬性是第幾頁,用法是http://127.0.0.1:8000/books/?page=1
        pnb = PageNumberPagination()
        #通過分頁器對象的paginate_queryset方法進行分頁,
        paged_book_list = pnb.paginate_queryset(book_obj_list,request,)
        #將分頁的數據進行序列化
        s_books = BookSerializers(paged_book_list,many=True)
        return Response(s_books.data)

settings配置文件:

REST_FRAMEWORK={

    # "DEFAULT_THROTTLE_RATES":{
    #     "visit_rate":"5/m",
    # },
    'PAGE_SIZE':5, #這是全局的一個每頁展示多少條的配置,但是一般不用它,因為不同的數據展示可能每頁展示的數量是不同的
}

如果我們不想用全局的page_size配置,我們自己可以寫個類來繼承分頁類組件,重寫裡面的屬性:

#引入分頁
from rest_framework.pagination import PageNumberPagination
class MyPagination(PageNumberPagination):
    page_size = 3 #每頁數據顯示條數
    page_query_param = 'pp'  #http://127.0.0.1:8000/books/?pp=1,查詢哪一頁的數據
    page_size_query_param = 'size' #如果我們顯示的一頁數據不夠你用的,你想臨時的多看展示一些數據,可以通過你設置的這個page_size_query_param作為參數來訪問:http://127.0.0.1:8000/books/?pp=2&size=5 #那麼你看到的雖然是第二頁,但是可以看到5條數據,意思是將page_size的數字臨時擴大了,每頁展示的數據就多了或者少了,看你的page_size_query_param設置的值
    max_page_size = 10 #最大每頁展示多少條,即便是你前端通過page_size_query_param臨時調整了page_size的值,但是最大也不能超過我們設置的max_page_size的值

class BookView(APIView):
    def get(self,request):
        '''
        查看所有書籍
        :param request:
        :return:
        '''
        book_obj_list = models.Book.objects.all()
        pnb = MyPagination()
        paged_book_list = pnb.paginate_queryset(book_obj_list,request,)
        s_books = BookSerializers(paged_book_list,many=True)
        return Response(s_books.data)

還有我們玩的繼承了ModelViewSet類的試圖類使用分頁器的寫法:

from rest_framework.viewsets import ModelViewSet

from rest_framework.pagination import PageNumberPagination
class MyPagination(PageNumberPagination):
    page_size = 3
    page_query_param = 'pp'
    page_size_query_param = 'size'
    max_page_size = 10

class BookView(ModelViewSet):
    queryset = models.Book.objects.all()
    serializer_class = BookSerializers
    pagination_class = MyPagination #配置我們自己寫的分頁類

還有個偏移分頁,瞭解一下就行了

from rest_framework.pagination import LimitOffsetPagination

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

-Advertisement-
Play Games
更多相關文章
  • BOM對象——History ~~~javascript history History ~~~ ...
  • BOM對象——Navigator ~~~javascript ~~~ ...
  • 鍵盤控制DIV移動 ~~~javascript ~~~ ...
  • 錯誤總會發生,每當您寫一些新的電腦代碼時。 JavaScript 調試 在沒有調試器的情況下寫 JavaScript 是有難度的。 您的代碼中也許包含了語法錯誤,或者邏輯錯誤,這些都難以診斷。 通常,如果 JavaScript 代碼包含錯誤,也不會發生任何事情。不會有錯誤消息,並且不會有任何可供查 ...
  • jQuery jQuery,顧名思義,也就是JavaScript和查詢(Query)極大地簡化了JavaScript開發人員遍歷HTML文檔、操作DOM、處理事件、執行動畫和開發Ajax。 jQuery是免費、開源的 輕量級(壓縮後只有幾十k) 強大的選擇器 出色的 DOM 操作的封裝 可靠的事件處 ...
  • 將有id和父級id的正常json數組改變為有children內嵌欄位的方法(俄羅斯套娃,可用於樹形控制項和樹形表格的生成,純js原生代碼,不需要其它依賴) ...
  • 場景 Dubbo環境搭建-ZooKeeper註冊中心: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103555470 在上面搭建好ZooKeeper註冊中心後,搭建管理控制台實現服務監控。 註: 博客: https://blo ...
  • 一、簡介 Swarm 是 Docker 官方提供的一款集群管理工具,其主要作用是把若幹台 Docker 主機抽象為一個整體,並且通過一個入口統一管理這些 Docker 主機上的各種 Docker 資源。 Docker Swarm 包含兩方面:一個企業級的 Docker 安全集群,以及一個微服務應用編 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...