javascriptnode.jshttpsaxios

How can I measure the response times of an http request in Node?


I am working on a solution that makes http requests to different web services, and I need to measure the response times (detailed), I am currently using the "node:https" module, but I would like to know if there is a Library or package that is not " request" since it is deprecated and with axios I have not managed to do it

I leave here an example of the code I use

import https from "node:https";

const NS_PER_SEC = 1e9;
const MS_PER_NS = 1e6;
const timings = {
  // use process.hrtime() as it's not a subject of clock drift
  startAt: process.hrtime(),
  dnsLookupAt: undefined,
  tcpConnectionAt: undefined,
  tlsHandshakeAt: undefined,
  firstByteAt: undefined,
  endAt: undefined,
};

let responseBody = "";

const req = https.request(
  {
    hostname: SERVICE_URL,
    port: 443,
    path: "/",
    method: "GET",
    timeout: 5000,

    headers: {
      "User-Agent":
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
      Accept: "*/*",
      "Accept-Language": "en-US,en;q=0.9",
      "Accept-Encoding": "gzip, deflate, br",
    },
  },
  onAnyMessage
);

async function onAnyMessage(res) {
  res.once("readable", () => {
    timings.firstByteAt = process.hrtime();
  });
  res.on("data", (chunk) => {
    responseBody += chunk;
  });
  res.on("end", () => {
    timings.endAt = process.hrtime();
    console.log(responseBody);
    console.log(getTimings(timings));
  });
}

function getTimings(eventTimes) {
  return {
    // There is no DNS lookup with IP address
    dnsLookup:
      eventTimes.dnsLookupAt !== undefined
        ? getHrTimeDurationInMs(eventTimes.startAt, eventTimes.dnsLookupAt)
        : undefined,
    tcpConnection: getHrTimeDurationInMs(
      eventTimes.dnsLookupAt || eventTimes.startAt,
      eventTimes.tcpConnectionAt
    ),
    // There is no TLS handshake without https
    tlsHandshake:
      eventTimes.tlsHandshakeAt !== undefined
        ? getHrTimeDurationInMs(
            eventTimes.tcpConnectionAt,
            eventTimes.tlsHandshakeAt
          )
        : undefined,
    firstByte: getHrTimeDurationInMs(
      eventTimes.tlsHandshakeAt || eventTimes.tcpConnectionAt,
      eventTimes.firstByteAt
    ),
    contentTransfer: getHrTimeDurationInMs(
      eventTimes.firstByteAt,
      eventTimes.endAt
    ),
    total: getHrTimeDurationInMs(eventTimes.startAt, eventTimes.endAt),
  };
}

/**
 * Get duration in milliseconds from process.hrtime()
 * @function getHrTimeDurationInMs
 * @param {Array} startTime - [seconds, nanoseconds]
 * @param {Array} endTime - [seconds, nanoseconds]
 * @return {Number} durationInMs
 */
function getHrTimeDurationInMs(startTime, endTime) {
  const secondDiff = endTime[0] - startTime[0];
  const nanoSecondDiff = endTime[1] - startTime[1];
  const diffInNanoSecond = secondDiff * NS_PER_SEC + nanoSecondDiff;

  return diffInNanoSecond / MS_PER_NS;
}

req.on("socket", (socket) => {
  socket.on("lookup", () => {
    timings.dnsLookupAt = process.hrtime();
  });
  socket.on("connect", () => {
    timings.tcpConnectionAt = process.hrtime();
  });
  socket.on("secureConnect", () => {
    timings.tlsHandshakeAt = process.hrtime();
  });
});

req.on("error", (err) => {
  console.log(err);
});

req.end();

Solution

  • got provides timings:

    import got from 'got';
    
    const response = await got.get('https://stackoverflow.com');
    
    console.log(response.timings);
    

    Result:

    {
      start: 1731862688177,
      socket: 1731862688178,
      lookup: 1731862688191,
      connect: 1731862689031,
      secureConnect: 1731862689048,
      upload: 1731862689048,
      response: 1731862689214,
      end: 1731862689228,
      error: undefined,
      abort: undefined,
      phases: {
        wait: 1,
        dns: 13,
        tcp: 840,
        tls: 17,
        request: 0,
        firstByte: 166,
        download: 14,
        total: 1051
      }
    }