RESTful

問題1:RESTful框架到底解決了什么問題?(URL具有自描述性、資源表述與視圖的解耦合、互操作性利用構建微服務以及集成第三方系統(tǒng)、無狀態(tài)性太高水平擴展能力)
問題2:項目在使用RESTful架構時有沒有遇到一些問題或隱患?(對資源訪問的限制、資源從屬關系檢查、避免泄露業(yè)務信息防范可能的攻擊)
補充:下面的幾個和安全性相關的響應頭在前面講中間件的時候提到過的。

  • X-Frame-Options:DENY
  • X-Content-Type-Options:nosniff
  • X-XSS-Protection:1;mode=block;
  • Strict-Transport-Security:max-age=3153600;
    問題3:如何保護API中的敏感信息以及防范重放攻擊?(摘要和令牌)
    推薦閱讀:《如何有效防止API的重放攻擊》。
使用djangorestframework

安裝djangorestframework(為了方便描述,以下同意簡稱drf)。
pip install djangorestframework
配置drf

INSTALLED_APPS = [
    
    'rest_framework',
    
]

REST_FRAMEWORK = {
    # 配置默認頁面大小
    'PAGE_SIZE': 10,
    # 配置默認的分頁類
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    # 配置異常處理器
    # 'EXCEPTION_HANDLER': 'api.exceptions.exception_handler',
    # 配置默認解析器
    # 'DEFAULT_PARSER_CLASSES': (
    #     'rest_framework.parsers.JSONParser',
    #     'rest_framework.parsers.FormParser',
    #     'rest_framework.parsers.MultiPartParser',
    # ),
    # 配置默認限流類
    # 'DEFAULT_THROTTLE_CLASSES': (),
    # 配置默認授權類
    # 'DEFAULT_PERMISSION_CLASSES': (
    #     'rest_framework.permissions.IsAuthenticated',
    # ),
    # 配置默認認證類
    # 'DEFAULT_AUTHENTICATION_CLASSES': (
    #     'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    # ),
}
編寫序列化器
from rest_framework import serializers
from rest_framewor.serializers import MpdelSerializer
from common.models import District, HouseType, Estate, Agent

class DistrictSerializer(ModelSerializer):
  class Meta:
    model = District
    fields = ('distid', 'name')

class HouseTypeSerializer(ModelSerializer):
  class Meta:
     model = HouseType
     fields = '__all__'

class AgentSerializer(ModelSerializer):
  class Meta:
    model = Agent
    fields = ('agentid', 'name', 'tel', 'servstar', 'certificated')

class EstateSerializer(ModelSerializer):
  district = serializers.SerializerMethodField()
  agents = serializers.SerializerMethodField()

  @staticmethod
  def get_agent(estate):
    return AgentSerializer(estate.agents, many = True).data

  @staticmethod
  def get_district(estate):
    return DistrictSerializer(estate.district).data
   
 class Meta;
    model = Estate
    fields = '__all__'
方法1:使用裝飾器
@api_view(['GET'])
@cache_page(timeout=None,cache='api')
def province(request):
  query = District.objects.filter(parent_isnull=True)
  serializer = DisterictSerializer(queryset, many=True)
  return Response(serializer.data)

@api_view(['GET'])
@cache_page(timeout=300, cache='api')
def cities(request, provid)
 queryset = District.objects.filter(parent__distid=provid)
  serializer = DistrictSerializer(queryset, many=True)
  return Response(serializer.data)
urlpattern = [
  path = ('districts/', views.provinces, name='districts'),
  path = ('districts/<int:provid>/', view.cities, name = 'cities')
]

說明:上面使用了Django自帶的視圖裝飾器(@cache_page)來實現(xiàn)API接口返回數(shù)據(jù)的緩存。

方法2:使用APIview及其子類

更好的復用代碼,不要重復發(fā)明“輪子”。

class HouseTypeApiView(CacheResponseMixin, ListAPIView):
  queryset = HouseType.objects.all()
  serializer_class = HouseTypeSerializer
urlpattern = [
  path('housetypes/', views.HouseTypeApiView.as_view(), name='housetypes'),
]

說明:上面使用了drf_extensions提供的CacheResponseMixin混入類實現(xiàn)了對接口數(shù)據(jù)的緩存。如果重寫了獲取數(shù)據(jù)的方法,可以使用drf_extensions提供的@Cache_response來實現(xiàn)對接口數(shù)據(jù)的緩存,也可以用自定義的函數(shù)來生成緩存中的key。當然還有一個選擇就是通過Django提供的@method_decorator裝飾器,將@cache_page裝飾器處理為裝飾方法裝飾器,這樣也能提供使用緩存服務。

drf-extensions配置如下所示。

# 配置DRF擴展來支持緩存API接口調用結果
REST_FRAMEWORK = {
  'DEFAULT_CACHE_RESPONSE_TIMEOUT' : 300,
  'DEFAULT_USER_CACHE' : 'default',
# 配置默認緩存單個對象的key函數(shù)  
  'DEFAULT_OBJECT_CACHE_KEY_FUNC':'rest_framework_extensions.utils.default_object_cache_key_func',
  # 配置默認緩存對象列表的key函數(shù)
  'DEFAULT_LIST_CACHE_KEY_FUNC' : 'rest_framework_extensions.utils.default_list_cache_key_func',
}
方法3:使用ViewSet及其子類
class HouseTypeView(CacheResponseMixin, viewsets.ModelViewSet):
  queryset = HouseType.objects.all()
  serializer_class = HouseTypeSerializer
  pagination_class = None
router = DefaultRoute()
router.register('housetypes',views.HouseTypeViewSet)

urlpattern += router.urls

djangorestframework提供了Bootstrap定制的頁面來顯示接口返回的JSON數(shù)據(jù),當然也可以使用POSTMAN這樣的工具來對API接口進行測試

補充說明

在這里順便提一下跟前端相關的幾個問題
問題一:如何讓瀏覽器能夠發(fā)起DELETE/PUT/PATCH?

<form method='post'>
  <input type="hiden" name="_mehthod" value="delete">
</form>
if request.method == 'POST' and '_method' in request.POST:
  request.method = request.POST['_method'].upper()
<script>
  $.ajax({
    'url' : '/api/provinces',
    'type' : 'put',
    'data' : {},
    'dataType' : 'json',
    'success' : 'functon(json){}',
    'error' : function(){}
});
  $.getJSON('api/provinces',function(json){});
</scritpt>

問題2:如何解決多個JavaScript庫之間某個定義(如$函數(shù))沖突的 問題?

<script src="js/jquery.min.js"></script>
<script src="js/abc.min.js"></script>
<script>
    // $已經(jīng)被后加載的JavaScript庫占用了
    // 但是可以直接用綁定在window對象上的jQuery去代替$
    jQuery(function() {
        jQuery('#okBtn').on('click', function() {});
    });
</script>
<script src="js/abc.min.js"></script>
<script src="js/jquery.min.js"></script>
<script>
    // 將$讓出給其他的JavaScript庫使用
    jQuery.noConflict();
    jQuery(function() {
        jQuery('#okBtn').on('click', function() {});
    });
</script>
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容