4. k6 核心 API 详解:HTTP 方法与请求控制

k6 的 http 模块是执行容量压测的核心驱动。本章深入解析 http.get/post/put/delete 方法、参数传递、Headers 设置、Cookies 管理以及超时与重试机制,帮助你在巡检脚本中精确控制每一个请求行为。

4.1 HTTP 方法:get / post / put / delete

k6 为每个标准 HTTP 动词提供了独立的 API 方法,所有方法均返回一个 Response 对象,包含状态码、响应体、耗时等关键指标。

方法 签名 典型场景
http.get(url, [params]) GET 请求 查询资源、健康检查、巡检探活
http.post(url, body, [params]) POST 请求 创建资源、提交表单、登录认证
http.put(url, body, [params]) PUT 请求 全量更新资源、配置下发
http.del(url, [params]) DELETE 请求 删除资源、清理测试数据
巡检脚本最佳实践: 在容量压测中,GET 和 POST 占比通常超过 80%。建议将 POST 请求的 body 参数化,避免硬编码导致脚本不可复用。
import http from 'k6/http';
import { check } from 'k6';

export default function () {
  // GET 请求
  let getRes = http.get('https://api.example.com/users/1');
  check(getRes, { 'GET status is 200': (r) => r.status === 200 });

  // POST 请求(JSON body)
  let payload = JSON.stringify({ name: 'test_user', role: 'admin' });
  let postRes = http.post('https://api.example.com/users', payload, {
    headers: { 'Content-Type': 'application/json' },
  });
  check(postRes, { 'POST status is 201': (r) => r.status === 201 });

  // PUT 请求
  let putRes = http.put('https://api.example.com/users/1', payload);
  check(putRes, { 'PUT status is 200': (r) => r.status === 200 });

  // DELETE 请求
  let delRes = http.del('https://api.example.com/users/1');
  check(delRes, { 'DELETE status is 204': (r) => r.status === 204 });
}

4.2 参数传递:Query、Body 与 URL 参数

k6 支持三种参数传递方式,分别对应不同的 HTTP 语义。在巡检脚本中,参数化是避免请求重复和触发缓存穿透的关键手段。

  • Query 参数: 直接拼接在 URL 中,或通过 params 对象的 params 字段传递。
  • Body 参数: 支持 string、Buffer、Object(自动 JSON 序列化)或 FormData。
  • URL 路径参数: 使用模板字符串动态拼接,适合 RESTful 风格。
import http from 'k6/http';

export default function () {
  // Query 参数方式一:URL 拼接
  let res1 = http.get('https://api.example.com/search?q=k6&page=1');

  // Query 参数方式二:params 对象
  let res2 = http.get('https://api.example.com/search', {
    params: { q: 'k6', page: '1' },
  });

  // Body 参数:JSON 对象自动序列化
  let res3 = http.post('https://api.example.com/orders', {
    userId: 123,
    items: ['sku_a', 'sku_b'],
  });

  // URL 路径参数:模板字符串
  let userId = 42;
  let res4 = http.get(`https://api.example.com/users/${userId}`);
}
参数传递避坑: 当使用 params 对象传递 Query 参数时,k6 会自动进行 URL 编码。如果参数值包含特殊字符(如 &、=),务必使用 params 对象而非手动拼接,避免破坏 URL 结构。

4.3 Headers 设置:全局与请求级

Headers 控制着请求的认证、内容协商、缓存策略等关键行为。k6 支持两种设置层级:全局默认 Headers 和 请求级 Headers,后者优先级更高。

层级 设置方式 作用域 覆盖规则
全局 http.defaults.headers 所有请求 被请求级同名 Header 覆盖
请求级 params.headers 单次请求 完全覆盖全局同名 Header
import http from 'k6/http';

// 设置全局默认 Headers
http.defaults.headers = {
  'User-Agent': 'k6-capacity-test/1.0',
  'Accept': 'application/json',
};

export default function () {
  // 请求级 Headers 会覆盖全局同名 Header
  let res = http.get('https://api.example.com/protected', {
    headers: {
      'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIs...',
      'X-Request-ID': `req-${__VU}-${__ITER}`,  // 动态追踪 ID
    },
  });
}
安全提醒: 不要在脚本中硬编码 或 。建议通过环境变量注入:__ENV.AUTH_,并在 CI/CD 流水线中安全传递。

4.4 Cookies 管理:自动与手动控制

k6 的 Cookie 管理分为 自动 Cookie Jar(默认启用)和 手动 Cookie 控制。在容量压测中,理解 Cookie 行为对模拟有状态用户至关重要。

k6 Cookie 管理流程 自动 Cookie Jar(默认) VU 级别隔离,自动存储/发送 Set-Cookie 自动解析并应用 支持 Domain / Path / Secure 过滤 手动 Cookie 控制 创建自定义 Cookie Jar 手动 set() / get() / delete() 跨 VU 共享 Cookie 状态 或 容量压测建议:使用自动 Cookie Jar 模拟真实用户,手动 Jar 用于特殊场景
import http from 'k6/http';
import { check } from 'k6';

export default function () {
  // 自动 Cookie Jar:登录后自动携带 Session
  let loginRes = http.post('https://api.example.com/login', {
    username: 'test', password: 'pass',
  });
  check(loginRes, { 'login success': (r) => r.status === 200 });

  // 后续请求自动携带 Cookie
  let profileRes = http.get('https://api.example.com/profile');
  check(profileRes, { 'profile access': (r) => r.status === 200 });
}

4.5 超时与重试机制

在容量压测中,网络抖动和系统过载是常态。k6 提供了精细的超时控制和灵活的重试策略,确保巡检脚本在异常条件下仍能稳定运行。

4.5.1 超时设置

超时分为三个独立维度,分别控制不同阶段的等待时间:

参数 默认值 说明
timeout 60s 整个请求的完成超时(连接 + 发送 + 等待 + 接收)
connectTimeout 10s TCP 连接建立超时
tlsHandshakeTimeout 10s TLS 握手超时
import http from 'k6/http';

export default function () {
  let res = http.get('https://slow-api.example.com/data', {
    timeout: '30s',              // 总超时 30 秒
    connectTimeout: '5s',        // 连接超时 5 秒
    tlsHandshakeTimeout: '5s',   // TLS 握手超时 5 秒
  });
}

4.5.2 重试机制

k6 本身不内置自动重试,但可以通过 check + 循环实现轻量级重试逻辑。对于需要严格重试的场景,推荐使用 k6/execution 模块控制重试次数和间隔。

import http from 'k6/http';
import { sleep } from 'k6';

const MAX_RETRIES = 3;
const RETRY_DELAY = 1; // 秒

export default function () {
  let retries = 0;
  let success = false;

  while (retries < MAX_RETRIES && !success) {
    let res = http.get('https://api.example.com/unstable', {
      timeout: '10s',
    });

    if (res.status === 200) {
      success = true;
      console.log(`Request succeeded on attempt ${retries + 1}`);
    } else {
      retries++;
      console.warn(`Attempt ${retries} failed with status ${res.status}`);
      if (retries < MAX_RETRIES) {
        sleep(RETRY_DELAY * retries); // 指数退避
      }
    }
  }

  if (!success) {
    console.error('All retries exhausted');
  }
}
巡检脚本重试策略:
  • 幂等请求(GET / PUT / DELETE): 建议重试 2-3 次,使用指数退避(1s, 2s, 4s)。
  • 非幂等请求(POST 创建资源): 谨慎重试,需配合幂等键(Idempotency-Key)防止重复创建。
  • 超时类错误: 优先增加 timeout 值,而非盲目重试。

4.6 综合示例:巡检脚本中的 HTTP 请求编排

以下示例整合了本章所有核心 API,展示一个完整的容量压测巡检请求流程:

import http from 'k6/http';
import { check, sleep } from 'k6';

// 全局配置
http.defaults.headers = {
  'Accept': 'application/json',
  'User-Agent': 'k6-capacity-inspection/2.0',
};

export default function () {
  // 1. 登录(POST + Cookie 自动管理)
  let loginPayload = { username: `user_${__VU}`, password: 'test123' };
  let loginRes = http.post('https://api.example.com/auth/login', loginPayload, {
    timeout: '15s',
  });
  check(loginRes, { 'login 200': (r) => r.status === 200 });

  // 2. 查询资源列表(GET + Query 参数)
  let listRes = http.get('https://api.example.com/items', {
    params: { page: 1, limit: 50 },
    timeout: '10s',
  });
  check(listRes, { 'list 200': (r) => r.status === 200 });

  // 3. 创建资源(POST + 自定义 Header)
  let createPayload = JSON.stringify({ name: `item_${__ITER}`, type: 'test' });
  let createRes = http.post('https://api.example.com/items', createPayload, {
    headers: { 'Content-Type': 'application/json', 'X-Idempotency-Key': `key_${__VU}_${__ITER}` },
    timeout: '20s',
  });
  check(createRes, { 'create 201': (r) => r.status === 201 });

  // 4. 更新资源(PUT)
  let updateRes = http.put(`https://api.example.com/items/${__VU}`, createPayload, {
    timeout: '10s',
  });
  check(updateRes, { 'update 200': (r) => r.status === 200 });

  // 5. 删除资源(DELETE + 重试)
  let delRetries = 0;
  while (delRetries < 2) {
    let delRes = http.del(`https://api.example.com/items/${__VU}`, { timeout: '8s' });
    if (check(delRes, { 'delete 204': (r) => r.status === 204 })) break;
    delRetries++;
    sleep(1);
  }

  sleep(1);
}
巡检脚本设计原则: 每个 VU 使用独立的 __VU 和 __ITER 构造请求数据,避免请求冲突。超时设置应比生产环境 P99 响应时间高 50%,防止正常波动触发误报。