加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

如何优雅的封装requests

发布时间:2020-12-14 04:44:03 所属栏目:百科 来源:网络整理
导读:搭建接口自动化测试框架,一般都要对post/get请求做封装。 一般的封装过程是, class MyRequest: def my_post(): """do something""" requests.post(url=url,json=data,headers=self.headers) def my_get(): """do something""" requests.get(url=url,params

搭建接口自动化测试框架,一般都要对post/get请求做封装。

一般的封装过程是,

class MyRequest:
    def my_post():
        """do something"""
        requests.post(url=url,json=data,headers=self.headers)
    def my_get():
        """do something"""
        requests.get(url=url,params=params,headers=self.headers)

然而,借助装饰器,可以实现更优雅的封装。

在这之前,先打开requests.api.request,看看源码。

# -*- coding: utf-8 -*-

"""
requests.api
~~~~~~~~~~~~

This module implements the Requests API.

:copyright: (c) 2012 by Kenneth Reitz.
:license: Apache2,see LICENSE for more details.
"""

from . import sessions


def request(method,url,**kwargs):
    """Constructs and sends a :class:`Request <Request>`.

    :param method: method for the new :class:`Request` object.
    :param url: URL for the new :class:`Request` object.
    :param params: (optional) Dictionary,list of tuples or bytes to send
        in the query string for the :class:`Request`.
    :param data: (optional) Dictionary,list of tuples,bytes,or file-like
        object to send in the body of the :class:`Request`.
    :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`.
    :param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`.
    :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`.
    :param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': file-tuple}``) for multipart encoding upload.
        ``file-tuple`` can be a 2-tuple ``('filename',fileobj)``,3-tuple ``('filename',fileobj,'content_type')``
        or a 4-tuple ``('filename','content_type',custom_headers)``,where ``'content-type'`` is a string
        defining the content type of the given file and ``custom_headers`` a dict-like object containing additional headers
        to add for the file.
    :param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth.
    :param timeout: (optional) How many seconds to wait for the server to send data
        before giving up,as a float,or a :ref:`(connect timeout,read
        timeout) <timeouts>` tuple.
    :type timeout: float or tuple
    :param allow_redirects: (optional) Boolean. Enable/disable GET/OPTIONS/POST/PUT/PATCH/DELETE/HEAD redirection. Defaults to ``True``.
    :type allow_redirects: bool
    :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy.
    :param verify: (optional) Either a boolean,in which case it controls whether we verify
            the server's TLS certificate,or a string,in which case it must be a path
            to a CA bundle to use. Defaults to ``True``.
    :param stream: (optional) if ``False``,the response content will be immediately downloaded.
    :param cert: (optional) if String,path to ssl client cert file (.pem). If Tuple,('cert','key') pair.
    :return: :class:`Response <Response>` object
    :rtype: requests.Response

    Usage::

      >>> import requests
      >>> req = requests.request('GET','https://httpbin.org/get')
      <Response [200]>
    """

    # By using the 'with' statement we are sure the session is closed,thus we
    # avoid leaving sockets open which can trigger a ResourceWarning in some
    # cases,and look like a memory leak in others.
    with sessions.Session() as session:
        return session.request(method=method,url=url,**kwargs)


def get(url,params=None,**kwargs):
    r"""Sends a GET request.

    :param url: URL for the new :class:`Request` object.
    :param params: (optional) Dictionary,list of tuples or bytes to send
        in the query string for the :class:`Request`.
    :param **kwargs: Optional arguments that ``request`` takes.
    :return: :class:`Response <Response>` object
    :rtype: requests.Response
    """

    kwargs.setdefault('allow_redirects',True)
    return request('get',**kwargs)


def options(url,**kwargs):
    r"""Sends an OPTIONS request.

    :param url: URL for the new :class:`Request` object.
    :param **kwargs: Optional arguments that ``request`` takes.
    :return: :class:`Response <Response>` object
    :rtype: requests.Response
    """

    kwargs.setdefault('allow_redirects',True)
    return request('options',**kwargs)


def head(url,**kwargs):
    r"""Sends a HEAD request.

    :param url: URL for the new :class:`Request` object.
    :param **kwargs: Optional arguments that ``request`` takes.
    :return: :class:`Response <Response>` object
    :rtype: requests.Response
    """

    kwargs.setdefault('allow_redirects',False)
    return request('head',**kwargs)


def post(url,data=None,json=None,**kwargs):
    r"""Sends a POST request.

    :param url: URL for the new :class:`Request` object.
    :param data: (optional) Dictionary,or file-like
        object to send in the body of the :class:`Request`.
    :param json: (optional) json data to send in the body of the :class:`Request`.
    :param **kwargs: Optional arguments that ``request`` takes.
    :return: :class:`Response <Response>` object
    :rtype: requests.Response
    """

    return request('post',data=data,json=json,**kwargs)


def put(url,**kwargs):
    r"""Sends a PUT request.

    :param url: URL for the new :class:`Request` object.
    :param data: (optional) Dictionary,or file-like
        object to send in the body of the :class:`Request`.
    :param json: (optional) json data to send in the body of the :class:`Request`.
    :param **kwargs: Optional arguments that ``request`` takes.
    :return: :class:`Response <Response>` object
    :rtype: requests.Response
    """

    return request('put',**kwargs)


def patch(url,**kwargs):
    r"""Sends a PATCH request.

    :param url: URL for the new :class:`Request` object.
    :param data: (optional) Dictionary,or file-like
        object to send in the body of the :class:`Request`.
    :param json: (optional) json data to send in the body of the :class:`Request`.
    :param **kwargs: Optional arguments that ``request`` takes.
    :return: :class:`Response <Response>` object
    :rtype: requests.Response
    """

    return request('patch',**kwargs)


def delete(url,**kwargs):
    r"""Sends a DELETE request.

    :param url: URL for the new :class:`Request` object.
    :param **kwargs: Optional arguments that ``request`` takes.
    :return: :class:`Response <Response>` object
    :rtype: requests.Response
    """

    return request('delete',**kwargs)

首先定义了1个request函数。

后面定义了get/options/head/post/put/patch/delete 6个函数。

后面的6个函数,内部都在调用第一个request函数。只是传参不同。

显而易见,源码已经按不同的method做了一次封装了。

我们自己的封装就不要再定义my_get/my_post了,直接在这层封装上,加入我们自己的额外代码就好了。

装饰器,就能把我们自己的额外代码,优雅的加上去。

装饰器,长这样,

def decorator(post):
    def wrap():
        post()
    return wrap

如果加到post函数上去,

@decorator
def post()

就等价于,

post = decorator(post)

看到没有,我们可以在decorator里面搞事情了!

在搞事情前,先建个MyRequest,把requests.api.request的代码原封不动的沾过来,加上我们的装饰器@method

from requests.api import request

class MyRequest:
    
    #  def request可以不用添加
    
    @method
    def get(self,**kwargs):
        r"""Sends a GET request.

        :param url: URL for the new :class:`Request` object.
        :param params: (optional) Dictionary,list of tuples or bytes to send
            in the query string for the :class:`Request`.
        :param **kwargs: Optional arguments that ``request`` takes.
        :return: :class:`Response <Response>` object
        :rtype: requests.Response
        """

        kwargs.setdefault('allow_redirects',True)
        return request('get',**kwargs)

    @method
    def options(self,**kwargs):
        r"""Sends an OPTIONS request.

        :param url: URL for the new :class:`Request` object.
        :param **kwargs: Optional arguments that ``request`` takes.
        :return: :class:`Response <Response>` object
        :rtype: requests.Response
        """

        kwargs.setdefault('allow_redirects',True)
        return request('options',**kwargs)

    @method
    def head(self,**kwargs):
        r"""Sends a HEAD request.

        :param url: URL for the new :class:`Request` object.
        :param **kwargs: Optional arguments that ``request`` takes.
        :return: :class:`Response <Response>` object
        :rtype: requests.Response
        """

        kwargs.setdefault('allow_redirects',False)
        return request('head',**kwargs)

    @method
    def post(self,**kwargs):
        r"""Sends a POST request.

        :param url: URL for the new :class:`Request` object.
        :param data: (optional) Dictionary,or file-like
            object to send in the body of the :class:`Request`.
        :param json: (optional) json data to send in the body of the :class:`Request`.
        :param **kwargs: Optional arguments that ``request`` takes.
        :return: :class:`Response <Response>` object
        :rtype: requests.Response
        """
        return request('post',**kwargs)

    @method
    def put(self,**kwargs):
        r"""Sends a PUT request.

        :param url: URL for the new :class:`Request` object.
        :param data: (optional) Dictionary,or file-like
            object to send in the body of the :class:`Request`.
        :param json: (optional) json data to send in the body of the :class:`Request`.
        :param **kwargs: Optional arguments that ``request`` takes.
        :return: :class:`Response <Response>` object
        :rtype: requests.Response
        """

        return request('put',**kwargs)

    @method
    def patch(self,**kwargs):
        r"""Sends a PATCH request.

        :param url: URL for the new :class:`Request` object.
        :param data: (optional) Dictionary,or file-like
            object to send in the body of the :class:`Request`.
        :param json: (optional) json data to send in the body of the :class:`Request`.
        :param **kwargs: Optional arguments that ``request`` takes.
        :return: :class:`Response <Response>` object
        :rtype: requests.Response
        """

        return request('patch',**kwargs)

    @method
    def delete(self,**kwargs):
        r"""Sends a DELETE request.

        :param url: URL for the new :class:`Request` object.
        :return: :class:`Response <Response>` object
        :rtype: requests.Response
        """

        return request('delete',**kwargs)

接着再来实现method装饰器,这里有点不同的是,装饰器作用在类的方法上面的,参数有些区别,

def method(f):
    # do something
    def send(self,*args,**kwargs):
        # do something
        return f(self,**kwargs)
    # do something
    return send

send的第一个参数为self,跟类方法对应。

第二、第三个参数兼容了get/post等不同的传参,

return f(self,**kwargs)
#  等价于
return get(self,**kwargs)
# 或
return post(self,**kwargs)

优雅!

至于装饰器里面的do something,可以是记录耗时,打印日志,重试机制,等。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读