源码目录结构

ApiResponse

这个类没啥好说的

class ApiResponse(Response):
"""
继承了requests模块中的Response类,重写了里面的raise_for_status方法
"""
def raise_for_status(self):
if hasattr(self, "error") and self.error:
raise self.error
Response.raise_for_status(self)

get_req_resp_record

这个函数的功能是获取请求记录和响应记录,源码分为4段来看

第1段

def get_req_resp_record(resp_obj: Response) -> ReqRespData:
"""
:param resp_obj: Response响应
:return: 返回自定义的ReqResData模型类
""" def log_print(req_or_resp, r_type):
"""
日志打印,格式为标准的json
"""
msg = f"\n================== {r_type} details ==================\n"
for key, value in req_or_resp.dict().items():
# 如果value中还包含着dict或者list,就把value转成json格式
if isinstance(value, dict) or isinstance(value, list):
value = json.dumps(value, indent=4, ensure_ascii=False) msg += "{:<8} : {}\n".format(key, value)
logger.debug(msg)

第1段代码就是定义了一个打印日志的函数,打印的日志解析为标准的json格式

第2段

# 记录实际请求信息(请求头、cookie信息、请求体)
request_headers = dict(resp_obj.request.headers)
request_cookies = resp_obj.request._cookies.get_dict() request_body = resp_obj.request.body
if request_body is not None:
try:
request_body = json.loads(request_body)
except json.JSONDecodeError:
# str: a=1&b=2
pass
except UnicodeDecodeError:
# bytes/bytearray: request body in protobuf
pass
except TypeError:
# neither str nor bytes/bytearray, e.g. <MultipartEncoder>
pass # lower_dict_keys的作用是将字典中的key大写转小写
request_content_type = lower_dict_keys(request_headers).get("content-type")
if request_content_type and "multipart/form-data" in request_content_type:
# upload file type
request_body = "upload file stream (OMITTED)" request_data = RequestData(
method=resp_obj.request.method,
url=resp_obj.request.url,
headers=request_headers,
cookies=request_cookies,
body=request_body,
)
# 在debug模式下打印请求日志
log_print(request_data, "request")

第2段代码是先获取request_headersrequest_cookiesrequest_body,然后将获取到的信息放入RequestData模型中,最后打印请求的信息

第3段

# 记录响应信息
resp_headers = dict(resp_obj.headers)
lower_resp_headers = lower_dict_keys(resp_headers)
content_type = lower_resp_headers.get("content-type", "") if "image" in content_type:
# response is image type, record bytes content only
response_body = resp_obj.content
else:
try:
# try to record json data
response_body = resp_obj.json()
except ValueError:
# only record at most 512 text charactors
resp_text = resp_obj.text
response_body = omit_long_data(resp_text) response_data = ResponseData(
status_code=resp_obj.status_code,
cookies=resp_obj.cookies or {},
encoding=resp_obj.encoding,
headers=resp_headers,
content_type=content_type,
body=response_body,
) # 在debug模式下打印响应日志
log_print(response_data, "response")

第3段代码是获取resp_headerscontent_typeresponse_body,最后将这些数据都放入ResponseData模型类中,最后打印响应日志

第4段

req_resp_data = ReqRespData(request=request_data, response=response_data)
return req_resp_data

最后这段就是将刚才的请求信息和响应信息全部放入ReqRespData模型中,最后get_req_resp_record函数返回的内容就是ReqRespData模型

HttpSession

requests.Session上进行了二次封装,该类包含4个方法,下面依次介绍

init

    def __init__(self):
super(HttpSession, self).__init__()
self.data = SessionData()

初始化方法,定义了data属性的默认值为SessionData模型,该模型包含了req_resps: List[ReqRespData] = []请求响应内容

update_last_req_resp_record

    def update_last_req_resp_record(self, resp_obj):
"""
update request and response info from Response() object.
"""
# TODO: fix
self.data.req_resps.pop()
self.data.req_resps.append(get_req_resp_record(resp_obj))

更新最新的请求响应记录,放入req_resps列表中

request

发送requests.Request请求,返回requests.Response响应,还做了以下事情

  • 1.设置了超时时间120s
  • 2.计算整个请求花费了多少时间
  • 3.定义了客户端ip地址和端口号、服务端ip地址和端口号
  • 4.计算了响应体的内容大小
  • 5.记录了消耗时间
  • 6.记录了request和response记录,包括重定向记录

_send_request_safe_mode

发送一个http请求,并捕获由于连接问题可能发生的任何异常

    def _send_request_safe_mode(self, method, url, **kwargs):
"""
Send a HTTP request, and catch any exception that might occur due to connection problems.
Safe mode has been removed from requests 1.x.
"""
try:
return requests.Session.request(self, method, url, **kwargs)
except (MissingSchema, InvalidSchema, InvalidURL):
raise
except RequestException as ex:
resp = ApiResponse()
resp.error = ex
resp.status_code = 0 # with this status_code, content returns None
resp.request = Request(method, url).prepare()
return resp

httprunner3源码解读(3)client.py的更多相关文章

  1. httprunner3源码解读(2)models.py

    源码目录结构 我们首先来看下models.py的代码结构 我们可以看到这个模块中定义了12个属性和22个模型类,我们依次来看 属性源码分析 import os from enum import Enu ...

  2. httprunner3源码解读(4)parser.py

    源码结构目录 可以看到此模块定义了4个属性和12个函数,我们依次来讲解 属性源码分析 # 匹配http://或https:// absolute_http_url_regexp = re.compil ...

  3. httprunner3源码解读(1)简单介绍源码模块内容

    前言 最近想着搭建一个API测试平台,基础的注册登录功能已经完成,就差测试框架的选型,最后还是选择了httprunner,github上已经有很多开源的httprunner测试平台,但是看了下都是基于 ...

  4. pyspider源码解读--调度器scheduler.py

    pyspider源码解读--调度器scheduler.py scheduler.py首先从pyspider的根目录下找到/pyspider/scheduler/scheduler.py其中定义了四个类 ...

  5. 如何判断一个Http Message的结束——python源码解读

    HTTP/1.1 默认的连接方式是长连接,不能通过简单的TCP连接关闭判断HttpMessage的结束. 以下是几种判断HttpMessage结束的方式: 1.      HTTP协议约定status ...

  6. HttpClient 4.3连接池参数配置及源码解读

    目前所在公司使用HttpClient 4.3.3版本发送Rest请求,调用接口.最近出现了调用查询接口服务慢的生产问题,在排查整个调用链可能存在的问题时(从客户端发起Http请求->ESB-&g ...

  7. Alamofire源码解读系列(五)之结果封装(Result)

    本篇讲解Result的封装 前言 有时候,我们会根据现实中的事物来对程序中的某个业务关系进行抽象,这句话很难理解.在Alamofire中,使用Response来描述请求后的结果.我们都知道Alamof ...

  8. MyBatis源码解读(3)——MapperMethod

    在前面两篇的MyBatis源码解读中,我们一路跟踪到了MapperProxy,知道了尽管是使用了动态代理技术使得我们能直接使用接口方法.为巩固加深动态代理,我们不妨再来回忆一遍何为动态代理. 我相信在 ...

  9. php-msf 源码解读【转】

    php-msf: https://github.com/pinguo/php-msf 百度脑图 - php-msf 源码解读: http://naotu.baidu.com/file/cc7b5a49 ...

随机推荐

  1. ecshop 首页调用指定分类下的销售排行

    /*首页调用指定分类下的销售排行*/ function get_cats_top10($cat = '') { $sql = 'SELECT cat_id, cat_name ' . 'FROM ' ...

  2. Linux系列(24) - chmod

    前言 在Unix和Linux的中,每个文件(文件夹也被看作是文件)都有三种权限:读.写.运行. 被授予权限的用户身份有三种:当前文件的拥有者,与拥有者属于同组者(同一个group),其他人 hello ...

  3. thinkphp5.0框架运行机制分享小结

    1 访问index.php 入口文件,定义应用目录,加载框架引导文件 <?php // [ 应用入口文件 ] // 定义应用目录 define('APP_PATH', __DIR__ . '/. ...

  4. Loj#6053-简单的函数【Min25筛】

    正题 题目链接:https://loj.ac/p/6053 题目大意 定义一个积性函数\(f(p^c)=p\ xor\ c\),求\(\sum_{i=1}^nf(i)\) 解题思路 异或这个东西不太好 ...

  5. P3343-[ZJOI2015]地震后的幻想乡【dp,数学期望】

    正题 题目链接:https://www.luogu.com.cn/problem/P3343 题目大意 给出\(n\)个点的一张无向图,每条边被修复的时间是\([0,1]\)的一个随机实数,求这张图联 ...

  6. P4640-[BJWC2008]王之财宝【OGF,Lucas定理】

    正题 题目链接:https://www.luogu.com.cn/problem/P4640 题目大意 \(n\)种物品,其中\(t\)种物品是有个数限制的,第\(i\)种限制为\(b_i\),求选出 ...

  7. P5137-polynomial【倍增】

    正题 题目链接:https://www.luogu.com.cn/problem/P5137 题目大意 \(T\)组数据给出\(n,a,b,p\)求 \[\left(\sum_{0=1}^na^ib^ ...

  8. Phalcon如何创建多模块并能进行访问 《Phalcon入坑指南系列 四》

    本系列目录 一.Phalcon在Windows上安装 <Phalcon入坑指南系列 一> 二.Phalcon入坑必须知道的功能<Phalcon入坑指南系列 二> 三.Phalc ...

  9. 9-threadLocal

    ThreadLocal 多个线程访问同一个共享变量时特别容易出现并发问题,特别是多线程需要对共享变量进行写入时.为了保证线程安全,一般使用者在访问共享变量的时候需要进行适当的同步,如图 同步的一般措施 ...

  10. Spring IOC Container原理解析

    Spring Framework 之 IOC IOC.DI基础概念 关于IOC和DI大家都不陌生,我们直接上martin fowler的原文,里面已经有DI的例子和spring的使用示例 <In ...