lyyyuna 的小花园

动静中之动, by

RSS

k6 协议支持

发表于 2026-03

k6 不只是 HTTP 测试工具,它还支持 WebSocket、gRPC 和 SSL/TLS 等协议。这篇把它们过一遍。

HTTP/2

k6 在发送 HTTPS 请求时,会自动和服务器协商升级到 HTTP/2(如果服务器支持的话),和浏览器的行为一样,不需要额外配置。

如果想确认某个请求实际用的是什么协议,可以检查响应对象的 proto 属性:

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

export default function () {
  const res = http.get('https://quickpizza.grafana.com');
  check(res, {
    'protocol is HTTP/2': (r) => r.proto === 'HTTP/2.0',
  });
  sleep(1);
}

HTTP/2 相比 HTTP/1.1 的主要改进是在单个 TCP 连接上实现了多路复用——多个请求/响应可以并行传输,不用排队等待。不过 TCP 层的丢包重传仍然会影响所有流,这个问题要到 HTTP/3(基于 QUIC/UDP)才能彻底解决。

WebSocket

WebSocket 提供全双工的通信通道,常见于需要服务端推送的场景——比如聊天、实时通知、在线协作。

k6 提供了两个 WebSocket 模块:

和 HTTP 测试不同,WebSocket 测试不是反复执行 default 函数,而是建立连接后通过事件循环来处理消息。基本结构:

import ws from 'k6/ws';
import { check } from 'k6';

export default function () {
  const url = 'wss://echo.websocket.org';
  const params = { tags: { my_tag: 'hello' } };

  const res = ws.connect(url, params, function (socket) {
    socket.on('open', () => console.log('connected'));
    socket.on('message', (data) => console.log('Message received: ', data));
    socket.on('close', () => console.log('disconnected'));
  });

  check(res, { 'status is 101': (r) => r && r.status === 101 });
}

ws.connect() 的第三个参数是一个回调函数,接收 socket 对象。在这个函数里注册事件处理器后,k6 会阻塞直到连接关闭。

定时器和超时

可以用 socket.setInterval 做周期性操作(比如定时发 ping),用 socket.setTimeout 设置超时后关闭连接:

import ws from 'k6/ws';
import { check } from 'k6';

export default function () {
  const url = 'wss://echo.websocket.org';

  const res = ws.connect(url, {}, function (socket) {
    socket.on('open', function () {
      console.log('connected');

      // 每秒发一次 ping
      socket.setInterval(function () {
        socket.ping();
        console.log('Pinging every 1sec');
      }, 1000);
    });

    socket.on('ping', () => console.log('PING!'));
    socket.on('pong', () => console.log('PONG!'));
    socket.on('close', () => console.log('disconnected'));

    // 2 秒后关闭连接
    socket.setTimeout(function () {
      console.log('2 seconds passed, closing the socket');
      socket.close();
    }, 2000);
  });

  check(res, { 'status is 101': (r) => r && r.status === 101 });
}

错误处理

通过 error 事件捕获连接过程中的错误:

socket.on('error', function (e) {
  if (e.error() != 'websocket: close sent') {
    console.log('An unexpected error occurred: ', e.error());
  }
});

gRPC

gRPC 是 Google 开源的 RPC 框架,使用 Protocol Buffers 做序列化,二进制传输,比 JSON 更快更紧凑。k6 从 v0.49.0 开始在核心模块 k6/net/grpc 中支持 gRPC,包括一元调用和流式调用。

加载 Proto 定义

k6 在发送 gRPC 请求前需要知道消息和服务的定义。两种方式:

从本地 .proto 文件加载:

import { Client } from 'k6/net/grpc';

const client = new Client();
client.load(['definitions'], 'hello.proto');

或者使用 gRPC 反射协议自动发现(需要服务端支持):

import { Client } from 'k6/net/grpc';

const client = new Client();
client.connect('127.0.0.1:10000', { reflect: true });

一元调用

一元调用和普通 HTTP 请求类似——发一个请求,收一个响应:

import { Client, StatusOK } from 'k6/net/grpc';
import { check, sleep } from 'k6';

const client = new Client();
client.load(['definitions'], 'hello.proto');

export default () => {
  client.connect('127.0.0.1:10000', {});

  const data = { greeting: 'Bert' };
  const response = client.invoke('hello.HelloService/SayHello', data);

  check(response, {
    'status is OK': (r) => r && r.status === StatusOK,
  });

  console.log(JSON.stringify(response.message));

  client.close();
  sleep(1);
};

流式调用

k6 支持服务端流、客户端流和双向流。以服务端流为例:

import { Client, Stream } from 'k6/net/grpc';
import { sleep } from 'k6';

const COORD_FACTOR = 1e7;
const client = new Client();

export default () => {
  if (__ITER == 0) {
    client.connect('127.0.0.1:10000', { plaintext: true, reflect: true });
  }

  const stream = new Stream(client, 'main.FeatureExplorer/ListFeatures', null);

  stream.on('data', function (feature) {
    console.log(
      `Found feature called "${feature.name}" at ${feature.location.latitude / COORD_FACTOR}, ${
        feature.location.longitude / COORD_FACTOR
      }`
    );
  });

  stream.on('end', function () {
    client.close();
    console.log('All done');
  });

  // 发送请求
  stream.write({
    lo: { latitude: 400000000, longitude: -750000000 },
    hi: { latitude: 420000000, longitude: -730000000 },
  });

  sleep(0.5);
};

客户端流和双向流的 API 类似,区别在于客户端可以多次调用 stream.write() 发送消息,最后调用 stream.end() 关闭发送端。

SSL/TLS

k6 默认就支持 TLS,只要你的请求 URL 用 https 就行。除此之外,k6 还提供了几个更细粒度的 TLS 配置:

response.timings.tls_handshaking 记录了 TLS 握手的耗时,方便你分析 TLS 对请求延迟的影响。

lyyyuna 沪ICP备2025110782号-1