源码目录结构

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. Java中的三大特性:封装、继承、多态

    封装: 概念:封装可以被认为是一个保护屏障,防止该类的代码和数据被其他类随意访问,适当的封装可以让代码更容易理解与维护,也加强了代码的安全性. 原则:将属性隐藏起来,若需要访问某个属性,提供公共方法对 ...

  2. uni-app跨平台框架介绍和快速入门

    前言: 首先今天主要介绍的是一个多平台的前端框架uni-app,关于多平台的前端框架网上有很多成熟的解决方案比如说Taro,React Native,Flutter等这些都是一些非常优秀的前端跨平台的 ...

  3. PHP 一个树为另一棵树的子结构 [TO BE CONTINUED]

    输入两棵二叉树A,B,判断B是不是A的子结构.(ps:我们约定空树不是任意一个树的子结构) <?php class TreeNode { private $val; private $left; ...

  4. nginx 常用教程网址

    nginx rewrite比较齐全的教程 http://www.bubuko.com/infodetail-1810501.html

  5. three.js 材质翻转

    刚学.这个鸟玩意儿卡了半天,记录一下. var skyBox = new THREE.Mesh(skyGeometry, skyMaterial); //创建一个完整的天空盒,填入几何模型和材质的参数 ...

  6. JavaScript 获取html元素

    1.通过ID获取: document.getElementById("idname"); 2.通过class.tagname获取: var wcyclass = document. ...

  7. Java程序的种类

    Java程序的种类 Application:Java应用程序,是可以由Java解释器直接运行的程序. Applet:即Java小应用程序,是可随网页下载到客户端由浏览器解释执行的Java程序. Ser ...

  8. 牛逼的磁盘检查工具duf

    1.部署 wget https://github.com/muesli/duf/releases/download/v0.5.0/checksums.txt wget https://github.c ...

  9. a标签刷新当前页面

    <a href="javascript:location.reload();">刷新页面</a>

  10. 哈工大知识图谱(Knowledge Graph)课程概述

    一.什么是知识图谱 知识(Knowledge)可以理解为 精炼的数据,知识图谱(Knowledge Graph)即是对知识的图形化表示,本质上是一种大规模语义网络 (semantic network) ...