菜单

网络拦截

相关源文件

网络拦截是 Cypress 的核心系统,它允许用户在测试中拦截、监视、模拟和修改 HTTP 请求和响应。与旧技术不同,cy.intercept() 命令可以拦截所有类型的 HTTP 请求,包括 XHR、fetch、页面加载和资源加载。

有关浏览器自动化和通信协议的信息,请参阅浏览器自动化和通信

系统概览

网络拦截系统位于浏览器和服务器之间,充当代理,可以观察和操纵网络流量。它提供了以下功能:

  1. 监视网络请求而不修改它们
  2. 使用静态数据模拟响应
  3. 动态修改出站请求
  4. 动态修改入站响应
  5. 延迟或限制响应以模拟网络条件
  6. 使用 cy.wait() 等待特定请求完成

来源:packages/net-stubbing/lib/server/middleware/request.ts60-200 packages/net-stubbing/lib/server/route-matching.ts5-139 packages/driver/src/cy/net-stubbing/add-command.ts176-317

架构

网络拦截系统同时实现在 Cypress driver(客户端)和 server 组件中

来源:packages/net-stubbing/lib/external-types.ts74-168 packages/driver/src/cy/net-stubbing/add-command.ts175-319 packages/net-stubbing/lib/server/middleware/request.ts24-200 packages/net-stubbing/lib/server/intercepted-request.ts10-225

核心概念

1. 路由匹配器

路由匹配器决定拦截哪些 HTTP 请求。匹配器可以是

  • URL 字符串模式(例如,/api/users/*
  • 正则表达式(例如,/\/api\/users\/\d+/
  • 包含以下选项的详细配置对象
属性类型描述
urlString/RegExp要匹配的 URL
methodString/RegExpHTTP 方法(GET、POST 等)
hostnameString/RegExp要匹配的主机名
pathString/RegExp要匹配的路径(包括查询字符串)
pathnameString/RegExp不带查询字符串的路径
query对象要匹配的查询参数
headers对象要匹配的请求头
认证对象Basic auth credentials
portNumber/Number[]要匹配的端口号
https布尔值仅匹配 HTTPS 或 HTTP 请求
times数字匹配的最大次数
middleware布尔值在非中间件处理程序之前运行

来源:packages/net-stubbing/lib/external-types.ts210-395 packages/driver/src/cy/net-stubbing/add-command.ts110-173

2. 路由处理程序

路由处理程序定义了拦截请求时发生的操作。处理程序可以是

  • 字符串(用作响应体)
  • JSON 对象(用作响应体)
  • 静态响应对象
  • 一个可以动态处理请求的函数

函数处理程序接收一个具有以下关键方法的请求对象

方法描述
req.reply()发送响应,而不让请求出站
req.continue()允许请求继续,可选地修改响应
req.redirect()将请求重定向到另一个 URL
req.destroy()模拟网络错误
req.on()订阅响应事件

来源:packages/driver/src/cy/net-stubbing/events/before-request.ts150-261 packages/net-stubbing/lib/external-types.ts397-399

3. 静态响应

静态响应允许为拦截的请求定义固定的响应

来源:packages/net-stubbing/lib/external-types.ts412-449 packages/driver/src/cy/net-stubbing/static-response-utils.ts24-62

请求生命周期和拦截过程

下图显示了拦截请求的完整生命周期

来源:packages/net-stubbing/lib/server/middleware/request.ts60-200 packages/net-stubbing/lib/server/middleware/response.ts21-84 packages/net-stubbing/lib/server/intercepted-request.ts132-224

路由匹配过程

当一个请求被拦截时,Cypress 会按照特定的顺序将其与已注册的路由进行匹配

来源:packages/net-stubbing/lib/server/route-matching.ts13-93 packages/net-stubbing/lib/server/route-matching.ts128-139

cy.intercept() 命令

cy.intercept() 命令是网络拦截的主要 API。它支持多种重载

来源:packages/driver/src/cy/net-stubbing/add-command.ts175-318 packages/net-stubbing/lib/external-types.ts490-517

使用别名和等待

要稍后引用拦截,您可以使用别名

来源:packages/net-stubbing/lib/external-types.ts532-566 packages/driver/src/cy/net-stubbing/wait-for-route.ts10-51

InterceptedRequest

网络拦截系统的核心是 InterceptedRequest 类,它代表一个正在被拦截的请求,并提供处理它的方法

InterceptedRequest 类管理请求的整个生命周期,包括

  • 为路由处理程序添加默认订阅
  • 处理 before:request、response 等事件
  • 发送静态响应或继续处理请求
  • 管理中间件执行顺序

来源:packages/net-stubbing/lib/server/intercepted-request.ts17-225

事件系统

网络拦截系统使用基于事件的架构来处理请求的不同阶段

事件描述可用数据
before:request在请求发送之前请求详情
before:response在响应发送到浏览器之前响应 + 请求
response在响应发送之前(在 before:response 之后)响应 + 请求
after:response响应发送之后响应 + 请求

处理程序可以使用 req.on() 订阅这些事件

来源: packages/driver/src/cy/net-stubbing/events/before-request.ts25-362 packages/driver/src/cy/net-stubbing/events/response.ts19-167 packages/driver/src/cy/net-stubbing/events/index.ts21-28

性能考量

使用网络拦截时

  1. 选择性拦截:仅拦截您需要存根或断言的请求,因为拦截所有请求可能会影响性能。

  2. 最小化修改:修改响应时,尽量做最小的改动,以避免性能影响。

  3. 响应流式传输:对于大型响应,Cypress 使用流式传输来高效处理数据,并提供限制响应的选项来模拟网络条件。

来源: packages/net-stubbing/lib/server/util.ts183-236

实现细节

正文处理

网络拦截系统处理各种类型的请求/响应正文

  • JSON:自动检测并进行适当的解析/字符串化
  • 文本:作为 UTF-8 字符串处理
  • 二进制:在拦截过程中保留为 Buffer 对象
  • HTML:自动检测 Content-type

该系统还可以正确处理

  • UTF-8 编码内容
  • 二进制内容,如图片
  • 表单数据
  • 包含非 ASCII 字符的 JSON

来源: packages/net-stubbing/lib/server/util.ts27-53 packages/net-stubbing/lib/server/util.ts266-286 packages/net-stubbing/test/unit/util-spec.ts8-101

CORS 处理

该系统自动处理 CORS(跨源资源共享)要求

  • 在响应上设置适当的 CORS 标头
  • 响应 CORS 预检请求
  • 保留身份验证凭据

这确保了即使跨不同源,拦截的请求也能正常工作。

来源: packages/net-stubbing/lib/server/util.ts110-141 packages/net-stubbing/lib/server/middleware/request.ts41-52

与其他 Cypress 系统的集成

网络拦截系统与其他 Cypress 系统集成

  • 在命令日志中记录
  • 为稍后使用 cy.wait() 进行别名
  • 测试重试和清理
  • 网络流量断言
  • 用于响应正文的 Fixture 加载

每个拦截的请求都可以设置别名、等待并能在测试代码中访问,从而可以对应用程序的网络行为进行强大的断言。

来源: packages/driver/src/cy/net-stubbing/add-command.ts229-237 packages/driver/src/cy/net-stubbing/wait-for-route.ts10-51