zoukankan      html  css  js  c++  java
  • 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

     

     

     

  • 相关阅读:
    解决阿里云服务器磁盘报警
    linux服务器启动报错UNEXPECTED INCONSISTENCY解决方法
    记一次gitlab添加用户收不到邮件的解决办法
    php7安装redis拓展
    centos6.5安装部署zabbix监控服务端和客户端
    centos-6.5安装部署LNMP环境
    centos6.5编译安装php7
    centos6.5新增加硬盘挂载并实现开机自动挂载
    简单快速部署samba服务器
    第177天:常用正则表达式(最全)
  • 原文地址:https://www.cnblogs.com/xiangwang1/p/12394955.html
Copyright © 2011-2022 走看看