解析器

Posted yeyangsen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解析器相关的知识,希望对你有一定的参考价值。

一 解析器的作用

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

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

 

二:解析器的局部使用

仅处理请求头content-type为application/json的请求体: parser_classes = [JSONParser, ]

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


class TestView(APIView):
    parser_classes = [JSONParser, ]

    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请求,响应内容)

 

三:解析器的全局使用

settings中配置:

REST_FRAMEWORK = {
    DEFAULT_PARSER_CLASSES:[
        rest_framework.parsers.JSONParser
        rest_framework.parsers.FormParser
        rest_framework.parsers.MultiPartParser
    ]

}

 

四:解析器源码分析

由request.data方法开始进行解析,Request类下的data方法:

@property
    def data(self):
        if not _hasattr(self, _full_data):
            self._load_data_and_files()
        return self._full_data_load_data_and_files(self)

self._load_data_and_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)

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

最终调用parser的解析方法来解析  parsed = parser.parse(stream, media_type, self.parser_context)

def parse(self, stream, media_type=None, parser_context=None):
    """
    Parses the incoming bytestream as JSON and returns the resulting data.
    """
    parser_context = parser_context or {}
    encoding = parser_context.get(encoding, settings.DEFAULT_CHARSET)

    try:
        decoded_stream = codecs.getreader(encoding)(stream)
        parse_constant = json.strict_constant if self.strict else None
        return json.load(decoded_stream, parse_constant=parse_constant)
    except ValueError as exc:
        raise ParseError(JSON parse error - %s % six.text_type(exc))

 

 

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

 

以上是关于解析器的主要内容,如果未能解决你的问题,请参考以下文章

如何将选定的微调器 id 传递给片段

链接器链接过程及相关概念解析

VSCode自定义代码片段——CSS选择器

VSCode自定义代码片段6——CSS选择器

编写自定义表达式解析器或使用ANTLR库?

Spring boot:thymeleaf 没有正确渲染片段