http.get()

Sends a GET request and calls end() for you, returning the ClientRequest.

Signature
http.get(url[, options][, callback])
  • Added in Node.js v0.3.6

Parameters

ParameterTypeDescription
$urlstring | URLTarget URL. May be omitted in favour of the options-only overload, http.get(options[, callback]).
$optionsoptionalObjectSame options as http.request(), merged over the parsed url and taking precedence. Setting method here is pointless — it is forced to 'GET'.
$callbackoptionalFunctionAdded as a one-time listener for the 'response' event. Receives the http.IncomingMessage.

Return value

<http.ClientRequest>The same ClientRequest that http.request() returns, already ended. Use it to attach an 'error' listener or to abort.

Errors

Throws synchronously if the request path contains illegal characters; connection and parse failures are emitted as 'error' on the returned ClientRequest, which crashes the process if unhandled.

Changelog

  • PHP v10.9.0The url parameter can be passed alongside a separate options object.
  • PHP v7.5.0The options parameter can be a WHATWG URL object.

http.get() is http.request() with two differences: method defaults to 'GET' and request.end() is called for you. Everything else — options, events, the returned stream — is identical.

When to reach for it

Use it for read-only calls where you have no body to write: polling an internal endpoint, pulling a JSON document, checking whether a URL is reachable. Because it ends the request immediately, it reads as a single expression and chains naturally with .on('error', ...).

What trips people up

  • You must consume the response. The docs are explicit about this. If you only look at statusCode and return, call res.resume() to drain the body — otherwise the socket is held and, under keep-alive, the agent pool fills up and later requests stall with no error.
  • Non-2xx is not an error. A 404 or a 500 invokes the callback normally. Check res.statusCode yourself.
  • Redirects are not followed. A 302 gives you an empty body and a location header; following it is your job.
  • No HTTPS. Use https.get(), which has an identical signature, for https:// URLs.
  • The callback is not a promise. Wrap it yourself if you want await.

Example

Example · javascript
const http = require('node:http');

http.get('http://127.0.0.1:8000/', (res) => {
  const { statusCode } = res;
  const contentType = res.headers['content-type'];

  if (statusCode !== 200) {
    res.resume(); // drain so the socket is released
    console.log('Request failed. Status:', statusCode);
    return;
  }
  if (!/^application\/json/.test(contentType)) {
    res.resume();
    console.log('Expected JSON, got:', contentType);
    return;
  }

  res.setEncoding('utf8');
  let raw = '';
  res.on('data', (chunk) => { raw += chunk; });
  res.on('end', () => {
    console.log(JSON.parse(raw));
  });
}).on('error', (err) => {
  console.log('Got error:', err.message);
});
// { data: 'Hello World!' }

When to use it

  • Poll an internal service's /health endpoint from a sidecar or watchdog
  • Pull a JSON config document at startup from a local metadata service
  • Check that a URL responds with 200 before starting dependent work
  • Fetch a text feed in a script that must run with zero dependencies

Frequently asked questions

What is the difference between http.get() and http.request()?

http.get() sets method to 'GET' and calls req.end() automatically; http.request() does neither. Everything else — the options, the returned ClientRequest, the 'response' callback — is identical, so use get() for read-only calls and request() whenever you need to write a body.

Does http.get() follow redirects?

No. A 301 or 302 invokes your callback with an empty body and a location header, and following it is your responsibility. Use fetch(), which follows redirects by default, if you do not want to write the loop yourself.

Why does my Node script hang after several http.get() calls?

You are not consuming the response bodies. Each unread IncomingMessage keeps its socket checked out of the default keep-alive agent, and once maxSockets is reached new requests queue forever. Call res.resume() on any response whose body you do not read.

More examples

Promise wrapper you can await

Turns the callback API into something awaitable. The three failure paths a naive wrapper misses are all here: a non-2xx status rejects instead of resolving with garbage, the body is drained before rejecting, and the request-level 'error' event is routed to reject rather than being left to crash the process.

Example · javascript
import http from 'node:http';

function getJSON(url, { timeoutMs = 5000 } = {}) {
  return new Promise((resolve, reject) => {
    const req = http.get(url, { signal: AbortSignal.timeout(timeoutMs) }, (res) => {
      if (res.statusCode < 200 || res.statusCode >= 300) {
        res.resume();
        reject(new Error(`HTTP ${res.statusCode} ${http.STATUS_CODES[res.statusCode]}`));
        return;
      }
      const chunks = [];
      res.on('data', (c) => chunks.push(c));
      res.on('end', () => {
        try {
          resolve(JSON.parse(Buffer.concat(chunks).toString('utf8')));
        } catch (err) {
          reject(err);
        }
      });
    });
    req.on('error', reject);
  });
}

const data = await getJSON('http://127.0.0.1:8000/status');
console.log(Object.keys(data).sort());

Following a redirect by hand

Neither http.get() nor http.request() follows redirects, unlike fetch() or curl -L. The two details that bite: a Location header is allowed to be relative, so it must be resolved against the current URL, and the hop count must be capped or a redirect loop recurses until the stack or the socket pool gives out.

Example · javascript
const http = require('node:http');

function get(url, redirectsLeft = 5) {
  return new Promise((resolve, reject) => {
    http.get(url, (res) => {
      const { statusCode, headers } = res;

      if (statusCode >= 300 && statusCode < 400 && headers.location) {
        res.resume(); // discard the redirect body
        if (redirectsLeft === 0) {
          reject(new Error('too many redirects'));
          return;
        }
        // location may be relative -- resolve it against the current URL
        const next = new URL(headers.location, url).toString();
        console.log(`${statusCode} -> ${next}`);
        resolve(get(next, redirectsLeft - 1));
        return;
      }

      let body = '';
      res.setEncoding('utf8');
      res.on('data', (c) => { body += c; });
      res.on('end', () => resolve({ statusCode, body }));
    }).on('error', reject);
  });
}

Discussion

  • Be the first to comment on this lesson.