zoukankan      html  css  js  c++  java
  • rest_framework:解析器

     

    一、解析器的作用

    根据请求头content-type选择对应的解析器对请求体内容进行处理。

    有application/json,x-www-form-urlencoded,form-data等格式

    二、局部使用解析器

    a、仅处理请求头content-type为application/json的请求体

    路由:

        url(r'^publish/$',views.PublishView.as_view()),

    视图:

    # 局部使用解析器
    from rest_framework.response import Response
    from rest_framework.request import Request
    from rest_framework.parsers import JSONParser
    class PublishView(APIView):
        parser_classes = [JSONParser,]
        # 获取所有的数据
        def get(self,request):
            publish_list=models.Publish.objects.all()
            ps=PublishSerializers(publish_list,many=True)
            return Response(ps.data)
        def post(self,request,*args,**kwargs):
            print(request.content_type)
            # 获取请求的值,并使用对应的jsonparser进行处理
            print(request.data)
            print(type(request.data))
    
            #application/x-www-form-urlencoded或multipart/form-data时,request.POST才有值
            print(request.POST)
            print(request.FILES)
            return Response('post请求,响应内容')
        def put(self,request,*args,**kwargs):
            return Response('put请求,响应内容')

    通过get方法可以获取数据,对数据新增的时候只有json这一种格式,使用其它方式新增数据提示失败,不支持

    b,仅处理请求头content-type为application/x-www-form-urlencodede的请求体

    设置url:

        url(r'^publish/$',views.TestView.as_view()),

    设置路由:

    
    
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.request import Request
    from rest_framework.parsers import FormParser

    class
    TestView(APIView): parser_classes = [FormParser,] def post(self,request,*args,**kwargs): print(request.content_type) # 获取请求的值,并使用对应的jsonparser进行处理 print(request.data) # application/x-www-form-urlencoded或multipart/form-data时,request.POST中才有值 print(request.POST) print(request.FILES) return Response('POST请求,响应内容') def put(self,request,*args,**kwargs): return Response('put请求,响应内容')

    c,仅处理请求头content-type为multipart/form-data的请求体

    设置url:

        url(r'^publish/$',views.TestView.as_view()),

    设置视图:

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.request import Request
    from rest_framework.parsers import FormParser
    from rest_framework.parsers import MultiPartParser
    # 只处理请求头content-type为multipart/from-data的请求体
    class TestView(APIView):
    parser_classes = [MultiPartParser,]
    def post(self,request,*args,**kwargs):
    print(request.content_type)
    # 获取请求的值,并使用对应的jsonparser进行处理
    print(request.data)
    # application/x-www-form-urlencoded或multipart/form-data,request.Post中才有值
    print(request.POST)
    print(request.FILES)
    return Response('POST请求,响应内容')
    def put(self,request,*args,**kwargs):
    return Response('put请求,响应内容')

    只允许form-data格式的请求,其它格式或请求全部会拒绝:

    新建一个前端页面提交新增数据输入框:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form action="http://127.0.0.1:8000/publish/" method="post" enctype="multipart/form-data">
        <input type="text" name="user" />
        <input type="text" name="city">
    
        <input type="submit" value="提交">
    
    </form>
    </body>
    </html>

    提交数据后返回页面:

    d,仅上传文件:

    路由:

        url(r'publish/(?P<filename>[^/]+)', views.TestView.as_view()),

    视图:

    # 只处理文件
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.request import Request
    from rest_framework.parsers import FileUploadParser
    
    class TestView(APIView):
        parser_classes = [FileUploadParser, ]
    
        def post(self, request, filename, *args, **kwargs):
            print(filename)
            print(request.content_type)
    
            # 获取请求的值,并使用对应的JSONParser进行处理
            print(request.data)
            # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
            print(request.POST)
            print(request.FILES)
            return Response('POST请求,响应内容')
    
        def put(self, request, *args, **kwargs):
            return Response('PUT请求,响应内容')

    编辑前端web页面:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form action="http://127.0.0.1:8000/publish/f1.numbers" method="post" enctype="multipart/form-data">
        <input type="text" name="user" />
        <input type="file" name="img">
    
        <input type="submit" value="提交">
    
    </form>
    </body>
    </html>

    前端页面展示:

    文件上传成功,获取返回值:

    e,同时多个Parser

    同时使用多个parser时,rest framework会根据请求头content-type自动进行对比,并使用对应parser

    设置路由:

        url(r'publish/', views.TestView.as_view()),

    视图:

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.request import Request
    from rest_framework.parsers import JSONParser, FormParser, MultiPartParser
    
    class TestView(APIView):
        parser_classes = [JSONParser, FormParser, MultiPartParser, ]
    
        def post(self, request, *args, **kwargs):
            print(request.content_type)
    
            # 获取请求的值,并使用对应的JSONParser进行处理
            print(request.data)
            # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
            print(request.POST)
            print(request.FILES)
            return Response('POST请求,响应内容')
    
        def put(self, request, *args, **kwargs):
            return Response('PUT请求,响应内容')

    支持:

    JSONParser, FormParser, MultiPartParser提交数据


    三、全局使用解析器
    在settings中设置:
    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES':[
            'rest_framework.parsers.JSONParser'
            'rest_framework.parsers.FormParser'
            'rest_framework.parsers.MultiPartParser'
        ]
    
    }

    路由设置:

    urlpatterns = [
        url(r'test/', TestView.as_view()),
    ]

    视图函数:

    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    class TestView(APIView):
        def post(self, request, *args, **kwargs):
            print(request.content_type)
    
            # 获取请求的值,并使用对应的JSONParser进行处理
            print(request.data)
            # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
            print(request.POST)
            print(request.FILES)
            return Response('POST请求,响应内容')
    
        def put(self, request, *args, **kwargs):
            return Response('PUT请求,响应内容')

    四、源码分析

    1 在调用request.data时,才进行解析,由此入手
        @property
        def data(self):
            if not _hasattr(self, '_full_data'):
                self._load_data_and_files()
            return self._full_data
            
    2 查看self._load_data_and_files()方法---->self._data, self._files = self._parse()
    
            def _parse(self):
                #用户请求头里content_type的值
                media_type = self.content_type
    
                #self.parsers 就是用户配置的parser_classes = [FileUploadParser,FormParser ]
                #self里就有content_type,传入此函数
                parser = self.negotiator.select_parser(self, self.parsers)
    
    3 查看self.negotiator.select_parser(self, self.parsers)
         def select_parser(self, request, parsers):
            #同过media_type和request.content_type比较,来返回解析器,然后调用解析器的解析方法
            #每个解析器都有media_type = 'multipart/form-data'属性
            for parser in parsers:
                if media_type_matches(parser.media_type, request.content_type):
                    return parser
            return None
        
    4 最终调用parser的解析方法来解析parsed = parser.parse(stream, media_type, self.parser_context)
    1 Request实例化,parsers=self.get_parsers()
        Request(
                    request,
                    parsers=self.get_parsers(),
                    authenticators=self.get_authenticators(),
                    negotiator=self.get_content_negotiator(),
                    parser_context=parser_context
                )
    2 get_parsers方法,循环实例化出self.parser_classes中类对象
        def get_parsers(self):
            return [parser() for parser in self.parser_classes]            
    
    3 self.parser_classes 先从类本身找,找不到去父类找即APIVIew 中的
        parser_classes = api_settings.DEFAULT_PARSER_CLASSES
    4 api_settings是一个对象,对象里找DEFAULT_PARSER_CLASSES属性,找不到,会到getattr方法
            def __getattr__(self, attr):
                if attr not in self.defaults:
                    raise AttributeError("Invalid API setting: '%s'" % attr)
    
                try:
                    #调用self.user_settings方法,返回一个字典,字典再取attr属性
                    val = self.user_settings[attr]
                except KeyError:
                    # Fall back to defaults
                    val = self.defaults[attr]
    
                # Coerce import strings into classes
                if attr in self.import_strings:
                    val = perform_import(val, attr)
    
                # Cache the result
                self._cached_attrs.add(attr)
                setattr(self, attr, val)
                return val
     5 user_settings方法 ,通过反射去setting配置文件里找REST_FRAMEWORK属性,找不到,返回空字典
        @property
        def user_settings(self):
            if not hasattr(self, '_user_settings'):
                self._user_settings = getattr(settings, 'REST_FRAMEWORK', {})
            return self._user_settings
  • 相关阅读:
    Jboss未授权访问漏洞复现
    jboss反序列化漏洞复现(CVE-2017-7504)
    JBoss 5.x / 6.x反序列化漏洞(CVE-2017-12149)复现
    CVE-2019-5418复现
    CVE-2018-3760复现
    windows第三方提权——FileZilla提权
    msf学习
    脚本木马学习
    sql head注入
    sql 盲注理解
  • 原文地址:https://www.cnblogs.com/yangzhaon/p/11147814.html
Copyright © 2011-2022 走看看