drf 和 cmdb总结

 

drf

  1. 什么是restful规范?

    它是一套规范(协议),它做了一些规则,让数据交互遵循这个规则。
    对我来说最明显的是他的method不同做不同的操作,之前增删改查要位数4个url。
    详细:
    1. https代替http,保证数据传输时安全。
    2. 在url中一般要体现api标识,这样看到url就知道他是一个api。
    http://www.luffycity.com/api/....(建议,因为他不会存在跨域的问题)
    http://api.luffycity.com/....
    假设:
    前段:https://www.luffycity.com/home
    后端:https://www.luffycity.com/api/
    3. 在接口中要体现版本
    http://www.luffycity.com/api/v1....(建议,因为他不会存在跨域的问题)
    注意:版本还可以放在请求头中
    http://www.luffycity.com/api/
    accept: ...

    4. restful也称为面向资源编程,视网络上的一切都是资源,对资源可以进行操作,所以一般资源都用名词。
    http://www.luffycity.com/api/user/

    5. 如果要加入一些筛选条件,可以添加在url中
    http://www.luffycity.com/api/user/?page=1&type=9

    6. 根据method不同做不同操作。

    7. 返回给用户状态码
    - 200,成功
    - 300,301永久 /302临时
    - 400,403拒绝 /404找不到
    - 500,服务端代码错误

    很多公司:
                  def get(self,request,*args,**kwargs):
                      result = {'code':1000,'data':None,'error':None}
                      try:
                          val = int('你好')
                      except Exception as e:
                          result['code'] = 10001
                          result['error'] = '数据转换错误'

                      return Response(result)
           
    8. 返回值
    GET http://www.luffycity.com/api/user/
    [
    {'id':1,'name':'alex','age':19},
    {'id':1,'name':'alex','age':19},
    ]
    POST http://www.luffycity.com/api/user/
    {'id':1,'name':'alex','age':19}

    GET http://www.luffycity.com/api/user/2/
    {'id':2,'name':'alex','age':19}

    PUT http://www.luffycity.com/api/user/2/
    {'id':2,'name':'alex','age':19}

    PATCH https//www.luffycity.com/api/user/2/
    {'id':2,'name':'alex','age':19}

    DELETE https//www.luffycity.com/api/user/2/

    9. 操作异常时,要返回错误信息

    {
              error: "Invalid API key"
          }
    10. 对于下一个请求要返回一些接口:Hypermedia AP
    {
    'id':2,
    'name':'alex',
    'age':19,
    'depart': "http://www.luffycity.com/api/user/30/"
    }
  2. drf提供了那些功能?

    路由
    url     -> UserView.as_view({"get":"list","post":'create'})
    url(\d+) -> UserView.as_view({"get":"retrive","patch/put/delete/})

    router = routers.DefaultRouter()
    router.register(r'users', views.UserView)
    视图
    APIView
    ListAPIView/CreateAPIView
    ModelViewSet
    版本
    局部配置
    全局配置
    认证
      当用户发来请求时,找到认证的所有类并实例化成为对象列表,然后将对象列表封装到新的request对象中。
      以后在视同中调用request.user
      在内部会循环认证的对象列表,并执行每个对象的authenticate方法,该方法用于认证,他会返回两个值分别会赋值给request.user/request.auth
    权限
    节流,如何实现?
    在缓冲存在类似于一个字典的结构:
    {
    用户标识:[11231212,12323123,123123123]
    }
    解析器,解析请求体中的数据,将其变成我们想要的格式。request.data
    筛选器(过滤器)
    分页
    序列化,对对象或对象列表(queryset)进行序列化操作以及表单验证的功能。
    渲染器
  3. drf组件认证的实现过程?

    from django.conf.urls import url,include
    from django.contrib import admin
    from . import views
    urlpatterns = [
       url(r'^login/$', views.LoginView.as_view()),
       url(r'^order/$', views.OrderView.as_view()),
       url(r'^user/$', views.UserView.as_view()),
    ]

    import uuid
    from django.shortcuts import render
    from django.views import View
    from django.views.decorators.csrf import csrf_exempt
    from django.utils.decorators import method_decorator
    from rest_framework.versioning import URLPathVersioning
    from rest_framework.views import APIView
    from rest_framework.response import Response

    from . import models

    class LoginView(APIView):

       def post(self,request,*args,**kwargs):
           user_object = models.UserInfo.objects.filter(**request.data).first()
           if not user_object:
               return Response('登录失败')
           random_string = str(uuid.uuid4())
           user_object.token = random_string
           user_object.save()
           return Response(random_string)

    class MyAuthentication:
       def authenticate(self, request):
           """
          Authenticate the request and return a two-tuple of (user, token).
          """
           token = request.query_params.get('token')
           user_object = models.UserInfo.objects.filter(token=token).first()
           if user_object:
               return (user_object,token)
           return (None,None)

    class OrderView(APIView):
       authentication_classes = [MyAuthentication, ]
       def get(self,request,*args,**kwargs):
           print(request.user)
           print(request.auth)
           return Response('order')

    class UserView(APIView):
       authentication_classes = [MyAuthentication,]
       def get(self,request,*args,**kwargs):
           print(request.user)
           print(request.auth)
           return Response('user')

    源码分析:
    import uuid
    from django.shortcuts import render
    from django.views import View
    from django.views.decorators.csrf import csrf_exempt
    from django.utils.decorators import method_decorator
    from rest_framework.versioning import URLPathVersioning
    from rest_framework.views import APIView
    from rest_framework.response import Response

    from . import models

    class LoginView(APIView):

       def post(self,request,*args,**kwargs):
           user_object = models.UserInfo.objects.filter(**request.data).first()
           if not user_object:
               return Response('登录失败')
           random_string = str(uuid.uuid4())
           user_object.token = random_string
           user_object.save()
           return Response(random_string)

    class MyAuthentication:
       def authenticate(self, request):
           """
          Authenticate the request and return a two-tuple of (user, token).
          """
           token = request.query_params.get('token')
           user_object = models.UserInfo.objects.filter(token=token).first()
           if user_object:
               return (user_object,token)
           return (None,None)

    class OrderView(APIView):
       authentication_classes = [MyAuthentication, ]
       def get(self,request,*args,**kwargs):
           print(request.user)
           print(request.auth)
           return Response('order')

    class UserView(APIView):
       authentication_classes = [MyAuthentication,]
       def get(self,request,*args,**kwargs):
           print(request.user)
           print(request.auth)
           return Response('user')



    class APIView(View):
       authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
       
    def dispatch(self, request, *args, **kwargs):
           """
          `.dispatch()` is pretty much the same as Django's regular dispatch,
          but with extra hooks for startup, finalize, and exception handling.
          """
           # ###################### 第一步 ###########################
           """
          request,是django的request,它的内部有:request.GET/request.POST/request.method
          args,kwargs是在路由中匹配到的参数,如:
              url(r'^order/(\d+)/(?P<version>\w+)/$', views.OrderView.as_view()),
              http://www.xxx.com/order/1/v2/
          """
           self.args = args
           self.kwargs = kwargs


           """
          request = 生成了一个新的request对象,此对象的内部封装了一些值。
          request = Request(request)
              - 内部封装了 _request = 老的request
              - 内部封装了 authenticators = [MyAuthentication(), ]
          """
           request = self.initialize_request(request, *args, **kwargs)
           self.request = request

    def initialize_request(self, request, *args, **kwargs):
           """
          Returns the initial request object.
          """
           parser_context = self.get_parser_context(request)

           return Request(
               request,
               parsers=self.get_parsers(),
               authenticators=self.get_authenticators(), # [MyAuthentication(),]
               negotiator=self.get_content_negotiator(),
               parser_context=parser_context
          )

       def get_authenticators(self):
           """
          Instantiates and returns the list of authenticators that this view can use.
          """
           return [ auth() for auth in self.authentication_classes ]
       
    class LoginView(APIView):
       authentication_classes = []
       def post(self,request,*args,**kwargs):
           user_object = models.UserInfo.objects.filter(**request.data).first()
           if not user_object:
               return Response('登录失败')
           random_string = str(uuid.uuid4())
           user_object.token = random_string
           user_object.save()
           return Response(random_string)

    class OrderView(APIView):
       # authentication_classes = [TokenAuthentication, ]
       def get(self,request,*args,**kwargs):
           print(request.user)
           print(request.auth)
           if request.user:
               return Response('order')
           return Response('滚')

    class UserView(APIView):
       同上
  4. drf组件中权限的实现过程?

    from rest_framework.permissions import BasePermission
    from rest_framework import exceptions

    class MyPermission(BasePermission):
       message = {'code': 10001, 'error': '你没权限'}
       def has_permission(self, request, view):
           """
          Return `True` if permission is granted, `False` otherwise.
          """
           if request.user:
               return True

           # raise exceptions.PermissionDenied({'code': 10001, 'error': '你没权限'})
           return False

       def has_object_permission(self, request, view, obj):
           """
          Return `True` if permission is granted, `False` otherwise.
          """
           return False
           






    class OrderView(APIView):
       permission_classes = [MyPermission,]
       def get(self,request,*args,**kwargs):
           return Response('order')


    class UserView(APIView):
       permission_classes = [MyPermission, ]
       def get(self,request,*args,**kwargs):
           return Response('user')


    REST_FRAMEWORK = {
       "PAGE_SIZE":2,
       "DEFAULT_PAGINATION_CLASS":"rest_framework.pagination.PageNumberPagination",
       "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
       "ALLOWED_VERSIONS":['v1','v2'],
       'VERSION_PARAM':'version',
       "DEFAULT_AUTHENTICATION_CLASSES":["kka.auth.TokenAuthentication",]
    }      
           
           
    源码分析:
    class APIView(View):
       permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
       
       def dispatch(self, request, *args, **kwargs):
           封装request对象
           self.initial(request, *args, **kwargs)
           通过反射执行视图中的方法

    def initial(self, request, *args, **kwargs):
           版本的处理
           # 认证
           self.perform_authentication(request)

           # 权限判断
           self.check_permissions(request)
           
           
           self.check_throttles(request)
           
       def perform_authentication(self, request):
           request.user

       def check_permissions(self, request):
           # [对象,对象,]
           for permission in self.get_permissions():
               if not permission.has_permission(request, self):
                   self.permission_denied(request, message=getattr(permission, 'message', None))
       def permission_denied(self, request, message=None):
           if request.authenticators and not request.successful_authenticator:
               raise exceptions.NotAuthenticated()
           raise exceptions.PermissionDenied(detail=message)
           
       def get_permissions(self):
           return [permission() for permission in self.permission_classes]
       
    class UserView(APIView):
       permission_classes = [MyPermission, ]
       
       def get(self,request,*args,**kwargs):
           return Response('user')
  5. drf组件中节流的实现方式?

    -实现原理?
    频率限制在认证、权限之后
    - 匿名用户,用IP作为用户唯一标记,但如果用户换代理IP,无法做到真正的限制。
    - 登录用户,用用户名或用户ID做标识。
    具体实现:
    在django的缓存中 = {
           throttle_anon_1.1.1.1:[100121340,],
           1.1.1.2:[100121251,100120450,]
      }


       限制:60s能访问3次
       来访问时:
           1.获取当前时间 100121280
           2.100121280-60 = 100121220,小于100121220所有记录删除
           3.判断1分钟以内已经访问多少次了? 4
           4.无法访问
       停一会
       来访问时:
           1.获取当前时间 100121340
           2.100121340-60 = 100121280,小于100121280所有记录删除
           3.判断1分钟以内已经访问多少次了? 0
           4.可以访问

    -具体流程?
    from rest_framework.views import APIView
    from rest_framework.response import Response

    from rest_framework.throttling import AnonRateThrottle,BaseThrottle

    class ArticleView(APIView):
       throttle_classes = [AnonRateThrottle,]
       def get(self,request,*args,**kwargs):
           return Response('文章列表')

    class ArticleDetailView(APIView):
       def get(self,request,*args,**kwargs):
           return Response('文章列表')
           
           
    class BaseThrottle:
       """
      Rate throttling of requests.
      """

       def allow_request(self, request, view):
           """
          Return `True` if the request should be allowed, `False` otherwise.
          """
           raise NotImplementedError('.allow_request() must be overridden')

       def get_ident(self, request):
           """
          Identify the machine making the request by parsing HTTP_X_FORWARDED_FOR
          if present and number of proxies is > 0. If not use all of
          HTTP_X_FORWARDED_FOR if it is available, if not use REMOTE_ADDR.
          """
           xff = request.META.get('HTTP_X_FORWARDED_FOR')
           remote_addr = request.META.get('REMOTE_ADDR')
           num_proxies = api_settings.NUM_PROXIES

           if num_proxies is not None:
               if num_proxies == 0 or xff is None:
                   return remote_addr
               addrs = xff.split(',')
               client_addr = addrs[-min(num_proxies, len(addrs))]
               return client_addr.strip()

           return ''.join(xff.split()) if xff else remote_addr

       def wait(self):
           """
          Optionally, return a recommended number of seconds to wait before
          the next request.
          """
           return None


    class SimpleRateThrottle(BaseThrottle):
       """
      A simple cache implementation, that only requires `.get_cache_key()`
      to be overridden.

      The rate (requests / seconds) is set by a `rate` attribute on the View
      class. The attribute is a string of the form 'number_of_requests/period'.

      Period should be one of: ('s', 'sec', 'm', 'min', 'h', 'hour', 'd', 'day')

      Previous request information used for throttling is stored in the cache.
      """
       cache = default_cache
       timer = time.time
       cache_format = 'throttle_%(scope)s_%(ident)s'
       scope = None
       THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES

       def __init__(self):
           if not getattr(self, 'rate', None):
               self.rate = self.get_rate()
           self.num_requests, self.duration = self.parse_rate(self.rate)

       def get_cache_key(self, request, view):
           """
          Should return a unique cache-key which can be used for throttling.
          Must be overridden.

          May return `None` if the request should not be throttled.
          """
           raise NotImplementedError('.get_cache_key() must be overridden')

       def get_rate(self):
           """
          Determine the string representation of the allowed request rate.
          """
           if not getattr(self, 'scope', None):
               msg = ("You must set either `.scope` or `.rate` for '%s' throttle" %
                      self.__class__.__name__)
               raise ImproperlyConfigured(msg)

           try:
               return self.THROTTLE_RATES[self.scope]
           except KeyError:
               msg = "No default throttle rate set for '%s' scope" % self.scope
               raise ImproperlyConfigured(msg)

       def parse_rate(self, rate):
           """
          Given the request rate string, return a two tuple of:
          <allowed number of requests>, <period of time in seconds>
          """
           if rate is None:
               return (None, None)
           num, period = rate.split('/')
           num_requests = int(num)
           duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
           return (num_requests, duration)

       def allow_request(self, request, view):
           """
          Implement the check to see if the request should be throttled.

          On success calls `throttle_success`.
          On failure calls `throttle_failure`.
          """
           if self.rate is None:
               return True

           # 获取请求用户的IP
           self.key = self.get_cache_key(request, view)
           if self.key is None:
               return True

           # 根据IP获取他的所有访问记录,[]
           self.history = self.cache.get(self.key, [])

           self.now = self.timer()

           # Drop any requests from the history which have now passed the
           # throttle duration
           while self.history and self.history[-1] <= self.now - self.duration:
               self.history.pop()
           if len(self.history) >= self.num_requests:
               return self.throttle_failure()
           return self.throttle_success()

       def throttle_success(self):
           """
          Inserts the current request's timestamp along with the key
          into the cache.
          """
           self.history.insert(0, self.now)
           self.cache.set(self.key, self.history, self.duration)
           return True

       def throttle_failure(self):
           """
          Called when a request to the API has failed due to throttling.
          """
           return False

       def wait(self):
           """
          Returns the recommended next request time in seconds.
          """
           if self.history:
               remaining_duration = self.duration - (self.now - self.history[-1])
           else:
               remaining_duration = self.duration

           available_requests = self.num_requests - len(self.history) + 1
           if available_requests <= 0:
               return None

           return remaining_duration / float(available_requests)


    class AnonRateThrottle(SimpleRateThrottle):
       """
      Limits the rate of API calls that may be made by a anonymous users.

      The IP address of the request will be used as the unique cache key.
      """
       scope = 'anon'

       def get_cache_key(self, request, view):
           if request.user.is_authenticated:
               return None  # Only throttle unauthenticated requests.

           return self.cache_format % {
               'scope': self.scope,
               'ident': self.get_ident(request)
          }
         
  6. 什么是jwt?优势?

    一般在前后端分离时,用于做用户认证(登录)使用的技术。
    jwt的实现原理:
    - 用户登录成功之后,会给前端返回一段token。
    - token是由.分割的三段组成。
    - 第一段:类型和算法信心
    - 第二段:用户信息+超时时间
    - 第三段:hs256(前两段拼接)加密 + base64url
    - 以后前端再次发来信息时
    - 超时验证
    - token合法性校验
    优势:
    - token只在前端保存,后端只负责校验。
    - 内部集成了超时时间,后端可以根据时间进行校验是否超时。
    - 由于内部存在hash256加密,所以用户不可以修改token,只要一修改就认证失败。
  7. drf中 GenericAPIView 的作用?

    GenericAPIView,桥梁,内部定义:get_queryset/get_serilizer/get_page...

    ListAPIView,CreateAPIView,RetrieveAPIView,UpdateAPIView,DestroyAPIView
  8. 前后端分离项目:跨域问题

    由于浏览器具有“同源策略”的限制。
    如果在同一个域下发送ajax请求,浏览器的同源策略不会阻止。
    如果在不同域下发送ajax,浏览器的同源策略会阻止。


    #### 解决跨域:CORS

    ```
    本质在数据返回值设置响应头

    from django.shortcuts import render,HttpResponse

    def json(request):
      response = HttpResponse("JSONasdfasdf")
      response['Access-Control-Allow-Origin'] = "*"
      return response
       
    ```



    #### 跨域时,发送了2次请求?

    在跨域时,发送的请求会分为两种:

    - 简单请求,发一次请求。

    设置响应头就可以解决 from django.shortcuts import render,HttpResponse

    def json(request): response = HttpResponse("JSONasdfasdf") response['Access-Control-Allow-Origin'] = "*" return response


    - 复杂请求,发两次请求。

    - 预检
    - 请求

    @csrf_exempt def put_json(request): response = HttpResponse("JSON复杂请求") if request.method == 'OPTIONS': # 处理预检 response['Access-Control-Allow-Origin'] = "*" response['Access-Control-Allow-Methods'] = "PUT" return response elif request.method == "PUT": return response


    ```
    条件:
      1、请求方式:HEAD、GET、POST
      2、请求头信息:
          Accept
          Accept-Language
          Content-Language
          Last-Event-ID
          Content-Type 对应的值是以下三个中的任意一个
                                  application/x-www-form-urlencoded
                                  multipart/form-data
                                  text/plain

    注意:同时满足以上两个条件时,则是简单请求,否则为复杂请求
    ```

    #### 总结

    1. 由于浏览器具有“同源策略”的限制,所以在浏览器上跨域发送Ajax请求时,会被浏览器阻止。
    2. 解决跨域
      - 不跨域
      - CORS(跨站资源共享,本质是设置响应头来解决)。
        - 简单请求:发送一次请求
        - 复杂请求:发送两次请求
  9. 序列化器中如何自定义字段?

    展示特殊的数据(choices、FK、M2M)可使用
    depth 
    source,无需加括号,在源码内部会去判断是否可执行,如果可执行自动加括号。【fk/choice】 
    SerializerMethodField,定义钩子方法。【m2m】
    

cmdb

  1. 为什么要开发cmdb?

    服务器资产信息的采集。
    原来用的Excel维护,越来越不准确。
    自动进行资产信息的采集以及变更。
    系统开发出来时候,可以自动化采集资产信息,并且给其他系统提供数据支持。
  2. cmdb架构以及实现?

    中控机,基于paramiko连接远程服务器执行命令进行采集;参考django的中间件的源码、工厂模式、反射 进行可插拔的式插件的管理;通过父类中的异常对子类中的方法进行约束; 单利模式处理日志; 错误堆栈信息; 基于线程池做并发;
    API,负责资产信息的入库以及资产变更处理(Q查询); 给其他系统提供数据支持,并且要做资产变更记录,为了以后搭建运维自动化平台,可以为其他系统提供restful接口做数据支持。
    管控平台,资产信息的管理 + 报表。  
  3. 资产采集方式?

    - paramiko
    - agent
    - ansible/saltstack
  4. cmdb资产多久采集一次?

    1天采集一次, cmdb采集的是物理机的资产信息,硬件资产不会经常进行变动。
  5. cmdb技术点?

    1. - 类的约束

      - 通过字符串的形式导入一个模块
     import importlib
    module = importlib.import_module("xxx.xx.xx.csss")
    ```
    • 反射,通过字符串形式去操作对象中属性

      getattr
      setattr
      delattr
      hasattr
    • 线程池的应用

    • 导入包时,自动加载 __init__.py

    • requests模块的应用

      requests.get(url='...')

      requests.post(url="...",data={})

      requests.post(url="...",json={})
    • 项目中容易被修改的值,可以放在配置文件中。

    • 开放封闭原则

      配置开放
      源码封闭
    • 工厂模式:简单工厂

      mode = "email"
      class Email(object):
      def send(self):
      pass

      class Wechat(object):
      def send(self):
      pass

      class Message(object):
      def send(self):
      pass
      def run():
      instance = None
      if mode == 'email':
      instance = Email()
      elif mode == 'wechat':
      instance = Wechat()
      elif mode == 'message':
      insance = Message()

      if not instance:
      print('配置异常')
      instance.send()

      run()
    • 工厂模式:工厂方法/抽象工厂

      mode = "xxx.xx.Email"
      class Email(object):
      def send(self):
      pass

      class Wechat(object):
      def send(self):
      pass

      class Message(object):
      def send(self):
      pass
      def run():
      根据反射到类,并实例化。
      instance.send()
      run()
  6. 你们公司有多少台服务器?

    100台左右物理机。
  7. 获取资产的命令?

    - 内存信息
    sudo dmidecode -q -t 17 2>/dev/null
    注意:linux上要提前安装 yum install dmidecode
    - 硬盘(安装MegaCli)
    sudo MegaCli -PDList -aALL
    - 网卡
    sudo ip link show
    sudo ip addr show
    - 主板
    sudo dmidecode -t1
    - CPU
    cat /proc/cpuinfo

 

 

 

posted on 2020-03-02 12:29  向往1  阅读(264)  评论(0编辑  收藏  举报

导航

……