API總結

1. 什麼是Webservice

WebService就是一個應用程序向外界暴露出一個能經過Web進行調用的API,也就是說能用編程的方法經過 Web 來調用這個應用程序。咱們把調用這個WebService的應用程序叫作客戶端,而把提供這個WebService的應用程序叫作服務端python

2. 什麼是RPC

RPC 全稱 Remote Procedure Call—— 遠程過程調用。在學校學編程,咱們寫一個函數都是在本地調用就好了。可是在互聯網公司,服務都是部署在不一樣服務器上的分佈式系統,如何調用呢? RPC 技術簡單說就是爲了解決遠程調用服務的一種技術,使得調用者像調用本地服務同樣方便透明。 下圖是客戶端調用遠端服務的過程:web

image.png

  1. 客戶端client發起服務調用請求。
  2. client stub能夠理解成一個代理,會將調用方法、參數按照必定格式進行封裝,經過服務提供的地址,發起網絡請求。
  3. 消息經過網絡傳輸到服務端。
  4. server stub接受來自socket的消息 。
  5. server stub將消息進行解包、告訴服務端調用的哪一個服務,參數是什麼 。
  6. 結果返回給server stub
  7. sever stub把結果進行打包交給socket
  8. socket經過網絡傳輸消息 。
  9. client slubsocket拿到消息。
  10. client stub解 包消息將結果返回給client。一個RPC框架就是把步驟2到9都封裝起來。

3. 談談你對RESTfull規範的認識?

一種軟件架構風格、設計風格,而不是標準,只是提供了一組設計原則和約束條件,規定如何編寫以及如何設置返回值、狀態碼等信息數據庫

# -–-–API與用戶的通訊協議: https -–-–-– 

# -–-–-–-–-– 域名 -–-–-–-–-–-–-–-–-–-– 
    # 應該儘可能將API部署在專用域名之下。 
    https://api.example.com

    #若是肯定API很簡單,不會有進一步擴展,能夠考慮放在主域名下 
    https://example.org/api
        
#----------- 版 本 ------------------
    # 應該將API的版本號放入URL。
    https://api.example.com/v1/ 
        #另外一種作法是,將版本號放在HTTP頭信息中,但不如放入URL方便和直觀 
        
# ------------ 路徑 ------------------
    #視網絡上任何東西都是資源,均使用名詞表示(可複數) 
    https://api.example.com/v1/zoos 
    https://api.example.com/v1/animals 
    https://api.example.com/v1/employees

# --------- method -------------------
    GET :從服務器取出資源(一項或多項) 
    POST:在服務器新建一個資源 
    PUT:在服務器更新資源(客戶端提供改變後的完整資源) 
    PATCH:在服務器更新資源(客戶端提供改變的屬性) 
    DELETE :從服務器刪除資源

# ---------- 過濾 ----------------------
    # 經過在url上傳參的形式傳遞搜索條件 
        https://api.example.com/v1/zoos?limit=10:指定返回記錄的數量
        https://api.example.com/v1/zoos?offset=10:指定返回記錄的開始位置
        https://api.example.com/v1/zoos?page=2&per_page=100:指定第幾頁,以及每頁的記錄
        https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回結果按照哪一個屬性排序,以及排序順序
        https://api.example.com/v1/zoos?animal_type_id=1:指定篩選條

#---------- 狀態碼 ------------
    200 OK:客戶端請求成功,通常用於GET和POST請求
    400 Bad Request:客戶端請求有語法錯誤,不能被服務器所理解。
    301 Moved Permanently:永久移動,請求的資源已被永久移動到新url,返回信息會包含新的url,瀏覽器會自動 定向到新url 
    401 Unauthorized:請求未經受權,這個狀態代碼必須和WWW-Authenticate報頭域一塊兒使用。
    403 Forbidden:服務器收到請求,可是拒絕提供服務。
    404 Not Found:請求資源不存在,舉個例子:輸入了錯誤的URL。
    500 Internal Server Error:服務器發生不可預期的錯誤。
    502 Bad Gateway: 充當網關或代理的服務器,從遠端接收到一個無效的請求
    503 Server Unavailable:服務器當前不能處理客戶端的請求,一段時間後可能恢復正常

# ------錯誤處理 --------------- 
狀態碼是4xx時,應返回錯誤信息,error當作key。 { error: "Invalid API key" } 


#------ 返回結果 -------------- 
    GET /collection:返回資源對象的列表(數組) 
    GET /collection/resource:返回單個資源對象 
    POST /collection:返回新生成的資源對象 
    PUT /collection/resource:返回完整的資源對象 
    PATCH /collection/resource:返回完整的資源對象 
    DELETE /collection/resource:返回一個空文檔

4. 接口的冪等性是什麼意思?

一個接口經過1次相同的訪問,再對該接口進行N次相同的訪問時,對資源不造影響就認爲接口具備冪等性 

GET,  # 第一次獲取結果、第二次也是獲取結果對資源都不會形成影響,冪等。 

POST, # 第一次新增數據,第二次也會再次新增,非冪等。 

PUT,  # 第一次更新數據,第二次不會再次更新,冪等。 

PATCH,# 第一次更新數據,第二次不會再次更新,非冪等。 

DELTE,# 第一次刪除數據,第二次不在再刪除,冪等。

5. 爲何要使用django rest framework框架?

# 在編寫接口時能夠不使用django rest framework框架, 

# 不使用:也能夠作,能夠用django的CBV來實現,開發者編寫的代碼會更多一些。 

# 使用:內部幫助咱們提供了不少方便的組件,咱們經過配置就能夠完成相應操做
    如:'序列化'能夠作用戶請求數據校驗 + queryset對象的序列化稱爲json
        '解析器'獲取用戶請求數據request.data,會自動根據content-type請求頭的不能對數據進行解析 
        '分頁'將從數據庫獲取到的數據在頁面進行分頁顯示。 
        
# 還有其餘組件:
    '認證'、'權限'、'訪問頻率控制

6. django rest framework框架中都有那些組件?

序列化、視圖、認證、權限、限制django

分頁、版本控制、過濾器、解析器、渲染器編程

7. django rest framework框架中的視圖均可以繼承哪些類?

image.png

# ---- 繼承APIView --------
# APIView繼承於View ,可是重寫了父類View中的dispatch(),將get、post、put的數據放入request。data中, 將請求的參數放入request.query_params
# ----繼承GenericAPIView----
# 每個接口都是生成一個序列化對象,實例化,調用data方法,對其進行封裝
class GenericAPIView(views.APIView):
    queryset = None
    serializer_class = None
    
# python mixin(混合類):不能單獨使用,和其它類搭配起來使用(利用了Python支持多繼承)
class PublisherList(GenericView,ListMixin,CreateMixin): 
    queryset = models.Publisher.objects.all() 
    serializer_class = PublisherSerializer
       
# -----繼承GenericViewSet ---------- 

# GenericViewSet(ViewSetMixin, generics.GenericAPIView):

# ViewSetMixin重寫了as.view()方法,實現了根據請求的方法執行具體的類方法

# 路由註冊的時候,利用actions參數,實現路由的定向分發 而不是簡單的 反射

url(r'authors/$', views.AuthorViewSet.as_view(actions={
                                                        'get': 'list',
                                                        'post': 'create'
                                                    })),

# 做者列表
url(r'authors/(?P<pk>\d+)/$', views.AuthorViewSet.as_view( actions={
                                                        'get': 'retrieve',
                                                        'put': 'update',
                                                        'delete': 'destroy'
                                                    })),


# -----繼承ModelViewSet ------
class ModelViewSet(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet)

#將不一樣的請求鏈接到不一樣的方法

8. django rest framwork 框架如何對QuerySet進行序列化?

序列化過程:ORM對象-->JSON格式數據 
反序列化:  JSON格式數據-->ORM對象

image.png

serializers.serializerjson

序列化過程:
    # (get請求)定義一個serializer類,繼承serializers.Serializer,定義字段告訴REST框架,哪些字段(field),須要被序列化/反序列化
    
    # 使用serializer類,將查詢結果集QuerySet傳入,並標明 many=True,表示序列化多個 獲得序列化的結果對象ser_obj,ser_obj.data即爲獲得的json格式的數據 反序列化過程:
    
1.如果post請求提交數據 request.data即爲提交的json格式的數據, 使用serializer類對   數據進行反序列化 -->ser_obj對象 
   對ser_obj對象進行is_vaild()校驗,此處能夠自定義校驗規則,具體參照上述表格        ser_obj.save()須要重寫serializer.create方法 


2.如果put請求: 
    根據pk去查詢具體的那本書籍對象obj 
    獲取用戶發送過來的數據而且更新對象, 賦值給instance的obj對象, partial=True的意識容許作局部更新 
    ser_obj = Serializer(instance=obj, data=request.data, partial=True) 
    對ser_obj對象進行is_vaild()校驗,此處能夠自定義校驗規則,具體參照上述表格       ser_obj.save() 須要重寫serializer.update方法

serializers.ModelSerializerapi

#序列化過程 - 不用定義字段
    class Meta:
        model = models.Book fields = "__all__"
        # depth = 1 # 全部有關係的字段都變成 read_only
        # exclude = [] # 排除某個字段
        extra_kwargs = { # 每一個字段的一些額外參數 
            'publisher': {'write_only': True},
            'authors': {'write_only': True},
            'category': {'write_only': True},
        } 
#反序列化的過程: 
#.save() 直接一鍵更新或建立,已經封裝了這兩個方法 
#另外:SerializerMethodField 會自動去找 get_字段名 的方法執行 
class BookModelSerializer(serializers.ModelSerializer):
    # SerializerMethodField 會自動去找 get_字段名 的方法執行 
    category_info = serializers.SerializerMethodField(read_only=True)
    publisher_info = serializers.SerializerMethodField(read_only=True)
    authors_info = serializers.SerializerMethodField(read_only=True)
    def get_category_info(self, book_obj):
        return book_obj.get_category_display()
    
    def get_publisher_info(self, book_obj):
        return PublisherSerializer(book_obj.publisher).data
    
    def get_authors_info(self, book_obj):
        return AuthorSerializer(book_obj.authors.all(), many=True).data
    
    class Meta: model = models.Book
        fields = "__all__"
        # depth = 1 # 全部有關係的字段都變成 read_only
        # exclude = [] # 排除某個字段
        extra_kwargs = { # 每一個字段的一些額外參數
            'publisher': {'write_only': True},
            'authors': {'write_only': True},
            'category': {'write_only': True},
        }

9. 簡述django rest framwork 框架的認證流程?

# 1.認證、權限和限制是在執行請求以前作的,路由-->as.view()-->APIView中的dispatch()方法中的 initial 方法 
    self.initial(request, *args, **kwargs)

# 2.在initial函數中
    # Ensure that the incoming request is permitted
    self.perform_authentication(request) # 認證
    self.check_permissions(request) # 權限
    self.check_throttles(request) # 限制

# 3.執行perform_authentication方法,其中request.user是一個@property的函數

# 4.在user方法中經過 self._authenticate()函數,去執行_authenticate()方法,將當前請求的用戶交給定義的在 authentication_classes=[]中的類的 authenticate進行身份驗證

# 5.實現 BaseAuthentication中的authenticate方法,返回元組,元組的第一個元素賦值給 request.user 第二個元素複製給了request.auth(token) 

# 6.如果authenticate方法 拋錯後,捕獲到報錯(raise),此時執行的 _not_authenticated 方法的,return 結果:user &auth 都賦值爲None

10. Token:jwt替代session存儲的方案

11. 簡述django rest framwork框架的權限實現

# 1.認證、權限和限制是在執行請求以前作的,路由-->as.view()-->APIView中的dispatch()方法中的initial方法
    self.initial(request, *args, **kwargs)
# 2.在initial函數中
    # Ensure that the incoming request is permitted 
    self.perform_authentication(request)  # 認證 
    self.check_permissions(request)  # 權限 
    self.check_throttles(request)  # 限制
    
# 3.執行 check_permissions方法,從當前 permission_classes 列表中,執行 has_permission()方法,判斷有沒有權限

# 4.實現BasePermission中的has_permission()方法
class MyPermission(BasePermission):
    message = '只有VIP才能訪問' 
    def has_permission(self, request, view): #經過上面的認證源碼得知:當不輸入token參數或者未登陸,則 user ,auth 均爲None,當auth存在則此時 的user不爲None
        if not request.auth:
            return False
        #當有Vip纔有權限訪問
        #if request.user當前通過認證的用戶對象
        if request.user.vip:
            return True else:
            #若是不是Vip就拒絕的範圍
            return False

# 5.若是存在驗證不經過,那麼就執行self.permission_denied,而後這個異常在dispatch函數中被捕捉,當作結果傳遞給response

12. DRF如何實現用戶訪問頻率控制 ( 匿名用戶,註冊用戶 )

# 1.如果未註冊用戶,因此不可能通過認證,則此時user,auth 均爲None

# 2.自定義allow_request方法 
    #拿到當前的請求的ip做爲訪問記錄的key 
    #把當前的請求的訪問記錄拿出來保存到一個變量中 
    #循環訪問歷史,把超過10 秒鐘的請求事件去掉 
    #在視圖或者全局中進行配置

throttle.py數組

# 使用內置限制類
from rest_framework.throttling import SimpleRateThrottle
class VisitThrottle(SimpleRateThrottle):
    scope = "xxx"
    def get_cache_key(self, request, view):
        return self.get_ident(request)

settings.py瀏覽器

# 在settings文件中進行配置
"DEFAULT_THROTTLE_CLASSES": {["BAR.XXX.VisitThrottle", ],
                             "DEFAULT_THROTTLE_RATES": {
                                 "xxx": "1/s",
                             }
相關文章
相關標籤/搜索