Python 测开27期 - 柒柒 - 接口协议抓包分析与mock

1. 网络模型

OSI七层模型

  • 应用层
  • 表示层
  • 会话层
  • 传输层
  • 网络层
  • 数据链路层
  • 物理层

TCP/IP四层模型

  • 应用层:DNS/TELNET/HTTP/FTP/SMTP/POP3
  • 传输层:TCP/UDP
  • 网络层:IP
  • 网络接口层

2. 常见的接口协议

RPC协议

  • RPC(Remote Procedure Call)
  • 以本地代码调用的方式实现远程执行
  • 主要用于公司内部的服务调用
  • 优点:传输效率更高、性能损耗更低、自带负载均衡策略、更好的服务治理能力
  • 常见的 RPC 协议:
    • Dubbo:Java 基础之上的高性能 RPC 协议
    • gRPC:高性能通用 RPC 框架,基于 Protocol Buffers。PB 是一个语言中立、平台中立的数据序列化框架
    • Thrift:与 gRPC 类似的多语言 RPC 框架

HTTP协议

  • 请求
    • 请求行:method url protocol
    • 请求方法:GET、POST、PUT、DELETE、HEAD
    • 请求头: Host Cookie User-Agent
    • 请求参数 query
    • 请求体:JSON XML FORM
  • 响应:
    • 响应状态行
    • 响应头
    • 响应体

HTTP 响应状态码

  • 1xx 临时响应,表示通知信息,请求收到了或正在进行处理
  • 2xx 表示成功,接受或知道了
    • 200 成功
  • 3xx 表示重定向,要完成请求还必须才去进一步的行动
    • 301 永久移动
    • 302 临时移动
  • 4xx 表示客户端请求错误
    • 403 未授权
    • 404 未找到
  • 5xx 表示服务端错误
    • 500 服务器内部错误
    • 503 服务不可用

RESTful 架构

  • Restful:Representational State Transfer
  • 借助于 HTTP 协议的基本请求方法代表资源的状态切换
    • GET:获取资源
    • POST:新增或者更新
    • PUT:更新资源
    • DELETE:删除资源

3. Mock

基于Charles

rewrite

  • mock by proxy:动态修改请求和响应中的数据,适用于全局修改或者修改内容简单的场景

map local

  • mock by stub:请求满足规则时,直接返回本地响应报文

map remote

  • 修改要访问的服务器地址
  • App 测试中,可以不用重新打包直接修改测试环境

基于Mitmproxy

核心组件

Addons(插件):Addons
Events(事件):Events

开启监听

  • mitmdump
    • -p 参数,指定监听端口,默认监听 8080
    • -s 参数,执行 python 脚本
      mitmdump -p 8999 -s xx/request_demo.py

实现 MapLocal

创建一个本地文件,设定响应数据
编写脚本,在请求事件中,即给响应对象复制
执行命令
访问浏览器验证结果
使用 http.HTTPResponse.make( )

from mitmproxy import http

# request 名称不能被改变
# mitmdump 加载这个脚本的时候,当有请求来的时候,就会回调这个request方法
# flow 为抓取到的请求信息
def request(flow: http.HTTPFlow) :
	# 发起请求,判断url是不是等于一个路径
	if flow.request.pretty_url == "http://example.com/path":
		# 打开本地的数据文件
		with open($path) as f:
			flow.response = http.HTTPResponse.make(
				200,  # 响应状态码
				f.read(),  响应体
				{"Content-Type": "application/json"}  # 响应头
			)

实现 Rewrite

from mitmproxy import http

# response 名称不能被改变
# mitmdump 加载这个脚本的时候,当拦截到响应之后,就会回调这个 response 方法
# flow 为抓取到的接口信息
def response(flow: http.HTTPFlow):
	# 添加过滤条件
	if flow.request.pretty_url == "http://example.com/path":
		# 使用json中的loads方法,把响应数据变成python对象
		data =  json.loads(flow.response.content)
		# 修改响应报文
		data['xx']['xxx'] = "xxxx"
		# 使用json中的dumps方法,将字典转为字符串
		# 再把字符串赋值给response的原始格式
		flow.response.text = json.dumps(data)