3

我目前正在评估 k6 是否适合我们的负载测试需求。我们有一个相当传统的网站架构,它使用带有 PHP 和 MySQL 数据库的 Apache 网络服务器。使用 k6 发送简单的 HTTP 请求看起来很简单,我认为我们将能够使用它测试所有主要功能,因为我们不太依赖 JavaScript,而且大多数页面都是静态的。

但是,我不确定如何处理请求中返回的 HTML 中引用的资源(样式表、图像等)。我们也需要加载它们,因为这有时会导致数据库请求,这必须是负载测试的一部分。

k6 中是否有一些开箱即用的功能,可以让您像浏览器一样加载所有资源?我知道 k6 不会呈现页面,我也不需要它。我只需要请求 HTML 中的所有资源。

4

2 回答 2

4

你基本上有两个选择,都有各自的注意事项:

  1. 记录您的会话-您可以直接从浏览器中导出 har,如图所示,或者使用为您的浏览器制作的扩展程序,这里是firefoxchromes。两者都应该可以在没有 k6 云帐户的情况下使用,您只需将它们设置为下载 har,当您点击停止时,它会自动(并且有点静默)下载它们。然后使用 k6 中的 har 转换器(已弃用,但仍然有效)或新的har-to-k6转换器。

    如果您有很多页面和/或资源,则此方法特别好,如果您有单页样式的应用程序甚至可以工作,因为它只是将浏览器请求的内容作为HAR获取,然后将其转换为脚本。如果没有需要输入的动态内容(用户名/密码),最终脚本大部分时间都可以使用。

    这种方法最大的问题是,如果你添加一个 css 文件,你需要重做整个练习。如果您在每次更改时更改 css/js 文件名或类似的东西,这将更加成问题。下一个方法有什么好处:

  2. 使用parseHTML,然后找到您关心的元素并为它们发出请求。
import http from "k6/http";
import {parseHTML} from "k6/html";

export default function() {
    const res = http.get("https://stackoverflow.com");
    const doc = parseHTML(res.body);
    doc.find("link").toArray().forEach(function (item) {
        console.log(item.attr("href"));
        // make http gets for it
        // or added them to an array and make one batch request
     });
}

会产生

NFO[0001] https://cdn.sstatic.net/Sites/stackoverflow/img/favicon.ico?v=4f32ecc8f43d
INFO[0001] https://cdn.sstatic.net/Sites/stackoverflow/img/apple-touch-icon.png?v=c78bd457575a
INFO[0001] https://cdn.sstatic.net/Sites/stackoverflow/img/apple-touch-icon.png?v=c78bd457575a
INFO[0001] /opensearch.xml
INFO[0001] https://cdn.sstatic.net/Shared/stacks.css?v=53507c7c6e93
INFO[0001] https://cdn.sstatic.net/Sites/stackoverflow/primary.css?v=d3fa9a72fd53
INFO[0001] https://cdn.sstatic.net/Shared/Product/product.css?v=c9b2e1772562
INFO[0001] /feeds
INFO[0001] https://cdn.sstatic.net/Shared/Channels/channels.css?v=f9809e9ffa90

正如您所看到的,一些 url 是相对的而不是绝对的,因此您需要处理这个问题。在这个例子中,只有一些是 css,所以可能需要更多的过滤。这里的问题是您需要编写代码,并且如果您添加相对链接或其他内容,您需要处理它。幸运的是,k6 是可编写脚本的,因此您可以重用代码:D。

于 2020-03-30T12:10:51.033 回答
3

我遵循了 Михаил Стойков 的建议并编写了自己的函数来加载资源。也许它可以帮助一些未来的读者。您可以设置资源的加载方式(使用 批量或顺序获取options.concurrentResourceLoading)。

/**
* @param {http.RefinedResponse<http.ResponseType>} response
*/
export function getResources(response) {
const resources = [];
response
    .html()
    .find('*[href]:not(a)')
    .each((index, element) => {
    resources.push(element.attributes().href.value);
    });
response
    .html()
    .find('*[src]:not(a)')
    .each((index, element) => {
    resources.push(element.attributes().src.value);
    });

if (options.concurrentResourceLoading) {
    const responses = http.batch(
    resources.map((r) => {
        return ['GET', resolveUrl(r, response.url), null, { headers: createHeader() }];
    })
    );
    responses.forEach(() => {
    check(response, {
        'resource returns status 200': (r) => r.status === 200,
    });
    });
} else {
    resources.forEach((r) => {
    const res = http.get(resolveUrl(r, response.url), {
        headers: createHeader(),
    });
    !check(res, {
        'resource returns status 200': (r) => r.status === 200,
    });
    });
}
}
于 2020-04-07T08:27:47.563 回答