• tornado解析http body的过程分析


    tornado解析http body的过程分析

    在最近写的一个RESTful API Server过程中,发现tornaod对解析POST BODY的内容有限制。

    而在以前用web.py则没有这个限制,使用httplib2作为客户端。

    客户端代码:

    复制代码
    def request(self, url, method, **kwargs):
            request_kwargs = copy.copy(kwargs)
            request_kwargs.setdefault('headers', kwargs.get('headers', {}))
            request_kwargs['headers']['Accept'] = 'application/json'
            request_kwargs['headers']['Content-type'] = 'application/x-www-form-urlencoded'
            try:
                request_kwargs['body']['token'] = self.token
                request_kwargs['body'] = urllib.urlencode(kwargs['body'])
            except KeyError:
                pass
            resp, body = super(HTTPClient, self).request(self.api_url + url, method, **request_kwargs)
            
            return resp, body
    复制代码

    上面加粗的部分中,设置header的Content-type参数,为 application/x-www-form-urlencoded,否则tornado不会解析request body中的内容。

    tornado解析uri中参数的过程就不解释了,关键的地方是解析body中的内容。

    body中可以有两种类型的内容,一为form提交的,二为被urlencod过的内容(也放在body)里面。

    因为httplib2在使用POST/PUT/PATCH提交body内容时,不会自动设置Content-type参数,导致了tornado找不到对应的类型。

    在使用self.get_argument函数时,根本得不到字段的内容。

    关键代码:

    首先是在HTTPConnection类中的_on_request_body回调函数:

    复制代码
    1 def _on_request_body(self, data):
    2         self._request.body = data
    3         if self._request.method in ("POST", "PATCH", "PUT"):
    4             httputil.parse_body_arguments(
    5                 self._request.headers.get("Content-Type", ""), data,
    6                 self._request.arguments, self._request.files)
    7         self.request_callback(self._request)
    复制代码

    httputil.parse_body_arguments函数完成对客户端使用POST/PATCH/PUT方法时,BODY内容的解析:

    复制代码
     1 def parse_body_arguments(content_type, body, arguments, files):
     2     """Parses a form request body.
     3 
     4     Supports "application/x-www-form-urlencoded" and "multipart/form-data".
     5     The content_type parameter should be a string and body should be
     6     a byte string.  The arguments and files parameters are dictionaries
     7     that will be updated with the parsed contents.
     8     """
     9     if content_type.startswith("application/x-www-form-urlencoded"):
    10         uri_arguments = parse_qs_bytes(native_str(body))
    11         for name, values in uri_arguments.iteritems():
    12             values = [v for v in values if v]
    13             if values:
    14                 arguments.setdefault(name, []).extend(values)
    15     elif content_type.startswith("multipart/form-data"):
    16         fields = content_type.split(";")
    17         for field in fields:
    18             k, sep, v = field.strip().partition("=")
    19             if k == "boundary" and v:
    20                 parse_multipart_form_data(utf8(v), body, arguments, files)
    21                 break
    22         else:
    23             logging.warning("Invalid multipart/form-data")
    复制代码

    函数的注释里面已经写的很清楚了:

    Supports "application/x-www-form-urlencoded" and "multipart/form-data".

    只支持 application/x-www-form-urlencoded 和 multipart/form-data这两种在body中提交内容的方式。

  • 相关阅读:
    快速幂模板
    ACM大一寒假集训week1.2
    ACM大一寒假集训week1.1
    Gym
    Gym
    大学ACM第八周心得
    大学ACM第六周心得(11.29)
    大学ACM第五周心得
    大学ACM第四周心得
    大学ACM第三周心得
  • 原文地址:https://www.cnblogs.com/DjangoBlog/p/5412382.html
Copyright © 2020-2023  润新知