RESTful

作者: 13147abc | 来源:发表于2019-03-03 15:04 被阅读0次

问题1:RESTful框架到底解决了什么问题?(URL具有自描述性、资源表述与视图的解耦合、互操作性利用构建微服务以及集成第三方系统、无状态性太高水平扩展能力)
问题2:项目在使用RESTful架构时有没有遇到一些问题或隐患?(对资源访问的限制、资源从属关系检查、避免泄露业务信息防范可能的攻击)
补充:下面的几个和安全性相关的响应头在前面讲中间件的时候提到过的。

  • 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)来实现API接口返回数据的缓存。

方法2:使用APIview及其子类

更好的复用代码,不要重复发明“轮子”。

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

说明:上面使用了drf_extensions提供的CacheResponseMixin混入类实现了对接口数据的缓存。如果重写了获取数据的方法,可以使用drf_extensions提供的@Cache_response来实现对接口数据的缓存,也可以用自定义的函数来生成缓存中的key。当然还有一个选择就是通过Django提供的@method_decorator装饰器,将@cache_page装饰器处理为装饰方法装饰器,这样也能提供使用缓存服务。

drf-extensions配置如下所示。

# 配置DRF扩展来支持缓存API接口调用结果
REST_FRAMEWORK = {
  'DEFAULT_CACHE_RESPONSE_TIMEOUT' : 300,
  'DEFAULT_USER_CACHE' : 'default',
# 配置默认缓存单个对象的key函数  
  'DEFAULT_OBJECT_CACHE_KEY_FUNC':'rest_framework_extensions.utils.default_object_cache_key_func',
  # 配置默认缓存对象列表的key函数
  '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数据,当然也可以使用POSTMAN这样的工具来对API接口进行测试

补充说明

在这里顺便提一下跟前端相关的几个问题
问题一:如何让浏览器能够发起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库之间某个定义(如$函数)冲突的 问题?

<script src="js/jquery.min.js"></script>
<script src="js/abc.min.js"></script>
<script>
    // $已经被后加载的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>

相关文章

网友评论

      本文标题:RESTful

      本文链接:https://www.haomeiwen.com/subject/lkgpuqtx.html