正确理解requests库的requests.Session()

request库的底层调用逻辑:

  最开始不理解requests.request() 和 requests.Session().request()方法时, 百度一下,发现很多讲的不够清楚,不够透彻. 可以说越讲越糊涂.

===============================================================

requests库发送请求的方式:

requests.get(url, params=None, **kwargs)
requests.post(url, data=None, json=None, **kwargs)
requests.put(url, data=None, **kwargs)
requests.delete(url, **kwargs)

 以上方法中返回的是如下方法

requests.request("get", url, params=params, **kwargs)
requests.request("post", url, data=data, json=json, **kwargs)
requests.request("put", url, data=data, **kwargs)
requests.request("delete", url, **kwargs)

即底层调用的是如下方法:   

requests.request(method, url, **kwargs)

如下是 requests.request()方法:

def request(method, url, **kwargs):
    with sessions.Session() as session:
        return session.request(method=method, url=url, **kwargs)

如上可以看出 requests.request() 方法调用了 sessions.py模块中的Session类的request方法

 

 

 sessions.py模块中的Session类的request方法具体内容:

    def request(
        self,  
        method,  # 请求方法
        url,     # 请求地址
        params=None,  # get请求入参
        data=None,    # post 或 put 请求入参
        headers=None, # 请求头
        cookies=None, # Cookie
        files=None,   # 文件上传
        auth=None,    # 鉴权
        timeout=None, # 超时处理
        allow_redirects=True, # 是否允许重定向
        proxies=None,  # 是否设置代理
        hooks=None,    # 钩子
        stream=None,   # 文件下载
        verify=None,   # 证书验证
        cert=None,     # CA认证
        json=None,     # post请求传参的一种方式
    ):
        """Constructs a :class:`Request <Request>`, prepares it and sends it.
        Returns :class:`Response <Response>` object.

        # Create the Request.
        req = Request(
            method=method.upper(),
            url=url,
            headers=headers,
            files=files,
            data=data or {},
            json=json,
            params=params or {},
            auth=auth,
            cookies=cookies,
            hooks=hooks,
        )
        prep = self.prepare_request(req)

        proxies = proxies or {}

        settings = self.merge_environment_settings(
            prep.url, proxies, stream, verify, cert
        )

        # Send the request.
        send_kwargs = {
            "timeout": timeout,
            "allow_redirects": allow_redirects,
        }
        send_kwargs.update(settings)
        resp = self.send(prep, **send_kwargs)

        return resp

 

requests库中的Session类是一个会话对象. 它可以在多个请求之间保持一些参数和状态,即自动关联cookie。通过创建一个Session对象,可以在该对象上执行多个请求,这样可以更有效地利用网络资源。

那么这样说来, 几种方式底层都一样, 都会自动关联cookie.  为什么在一个测试类中既有登录接口用例,又有其他接口用例.  我们执行时,  登录接口已经请求成功, 但是后面的接口请求返回的结果是 403 或者 未登录呢 ?  原因是 虽然requests.Session() 可以自动关联cookie, 但是 两个接口使用的并不是同一个requests.Session()对象.  所以他们之间是独立的请求. 是没有关联关系的.  怎么办呢,  这就需要我们创建一个session对象:  session = requests.Session() .   并统一使用该session对象发送请求: session.request(method,url,**kwargs).  这样用例中的请求就在一个会话中.  如 :  在登录之后, cookie信息就存在session对象中,后续的接口请求依然使用该session对象来发送请求, 就可以发送成功. 

 

import requests


class SendRequest:
    '''
    定义一个发送请求的类
    '''

    """
    web项目的接口都存在cookie关联. 使用requests.Session()对象来统一发送请求会自动关联所有请求的cookie信息.
    requests.Session().request()基于http长连接sokcet,保留历史请求的状态,这就对依赖于登陆状态的二次请求提供了很便利的途径
    """

    s = requests.Session()  # 创建一个session对象( 类变量 ).

    def send_request(self,method,url,**kwargs):
        '''
        封装一个统一请求.  
     为什么??? 所有请求都调用该方法发送, 而该方法是使用上面创建的session对象发送. 这样所有的请求是使用该session对象发送. 这样多个请求都会保持在一个会话中.
''' try: res = SendRequest.s.request(method,url,verify=False,**kwargs) # 调用类变量: 类名.类变量 except Exception as e: raise e.args else: return res

 

 

import json
import pprint

from Slience.utils.request_util import SendRequest


class Test001:
    def setup_class(self):
        # 登录
        method = 'post'
        url = 'http://127.0.0.1/api/mgr/signin'
        userinfo = {'username': 'byhy', 'password': '88888888'}
        # 使用同一个session对象发送请求, 保持在一个会话中
        res = SendRequest().send_request(method,url,data=userinfo)
        # print(res.json())
        return res

    def test_search_customer(self):
        # 查询客户
        method = 'GET'
        url = 'http://127.0.0.1/api/mgr/customers'
        data = {
            "action": "list_customer",
            "pagesize": 100,
            "pagenum": 1,
            "keywords": "人民医院"
        }
        # 使用同一个session对象发送请求, 保持在一个会话中
        res = SendRequest().send_request(method, url, params=data)
        print(json.dumps(res.json(),ensure_ascii=False,indent=4))
        return res

    def test_search_medicines(self):
        # 查询药品
        method = 'GET'
        url = 'http://127.0.0.1/api/mgr/medicines'
        data = {
            "action": "list_medicine",
            "pagesize": 100,
            "pagenum": 1,
            "keywords": ""
        }
        # 使用同一个session对象发送请求, 保持在一个会话中
        res = SendRequest().send_request(method, url, params=data)
        pprint.pprint(res.json())
        return res

    def teardown_class(self):
        '''
        关闭会话
        '''
        SendRequest.s.close()

 

 

 

阅读资料: 

 

Python的requests库中的Session类是一个会话对象,它可以在多个请求之间保持一些参数和状态。通过创建一个Session对象,可以在该对象上执行多个请求,这样可以更有效地利用网络资源。

使用Session对象可以做到以下几点:

1. 自动管理cookies:Session对象会自动处理请求和响应中的cookies,可以自动保存和发送cookies,无需手动处理。

2. 保持参数和状态:Session对象可以在多个请求之间保持一些参数和状态,例如HTTP头、身份验证信息等。这样可以避免在每个请求中重复设置这些参数。

3. 使用连接池:Session对象使用底层的urllib3库,可以使用连接池来管理和重用HTTP连接,提高性能。

使用Session对象的一般流程如下:

1. 创建一个Session对象:session = requests.Session()

2. 使用Session对象发送请求:response = session.get(url)

3. 处理响应:可以像使用requests库一样处理响应,例如获取响应内容、状态码等。

4. 使用Session对象发送其他请求:可以继续使用session对象发送其他请求,它会自动处理cookies和其他参数。

5. 关闭会话:session.close(),如果不主动关闭,会话会一直保持。

总之,Session对象可以方便地管理HTTP会话,提高请求的性能和灵活性。

 

posted @ 2023-08-17 12:56  Avicii_2018  阅读(5502)  评论(0编辑  收藏  举报