Browser DNS Resolution Behavior: Detailed Analysis of Multiple A Records Handling in HTTP Requests


2 views

When browsers receive multiple A records for a hostname, their behavior follows specific patterns that developers should understand for reliable application delivery. Here's what happens under the hood:

// Example DNS lookup simulation
const dns = require('dns');
dns.resolve('example.com', 'A', (err, addresses) => {
  console.log(Resolved IPs: ${addresses});
  // Typical output: ["192.0.2.1", "192.0.2.2"]
});

Modern browsers implement these behaviors:

  • Full DNS Record Retrieval: Browsers typically get all A records from the OS DNS resolver
  • Round-Robin Selection: Most browsers use the first IP initially but implement rotation for subsequent requests
  • Timeout Handling: Chrome waits ~3 seconds before trying next IP (varies by browser version)

Here's how browsers handle failed connections:

  1. Attempt connection to primary IP
  2. Wait for timeout (typically 3-21 seconds based on browser)
  3. Mark IP as "bad" temporarily (5-30 minute cache duration)
  4. Try next available IP
Browser Initial IP Selection Timeout Bad IP Cache
Chrome First IP 3s 5 minutes
Firefox Random 21s 30 minutes
Safari First IP 15s 10 minutes

Key caching characteristics:

// Chrome network internals flag to check DNS cache
chrome://net-internals/#dns
  • Browsers respect DNS TTL but often impose minimums (Chrome: 1 minute)
  • Refresh actions may trigger new DNS lookups if cache expired
  • Working IPs are often preferred until DNS cache expires

When implementing DNS-based failover:

# Python example checking DNS resolution
import socket
def check_dns(hostname):
    try:
        return socket.gethostbyname_ex(hostname)[2]
    except socket.gaierror:
        return []

Recommendations:

  • Set DNS TTL ≥ 60 seconds to match browser minimums
  • Implement health checks at application layer
  • Consider browser timeout behaviors in your SLA

When a browser receives multiple A records for a hostname, the behavior varies across implementations. Chrome (v115+) and Firefox (v116+) both perform complete DNS resolution through the OS resolver, obtaining all available IPs simultaneously rather than single IPs sequentially.

The current industry-standard approach follows this sequence:

// Pseudo-code for browser connection logic
function attemptConnection(hostname) {
  const ipList = dns.resolve(hostname); // Gets ALL A records
  const sortedIPs = applySortingAlgorithm(ipList);
  
  for (const ip of sortedIPs) {
    try {
      const socket = new Socket(ip);
      socket.timeout = 3000; // Default timeout
      await socket.connect();
      return socket;
    } catch (error) {
      continue; // Try next IP
    }
  }
  throw new Error("All IPs failed");
}

Key timing parameters observed in browser network stacks:

  • Initial connection timeout: 3 seconds (configurable via about:config/net-internals)
  • Total retry duration: 21 seconds (Chrome) or 18 seconds (Firefox)
  • DNS cache TTL: Respects record TTL but minimum 1 minute (browser-imposed floor)

Experimental observations with Chrome:

// Test case demonstrating refresh behavior
describe('DNS Failover Test', () => {
  it('should rotate IPs after failure', () => {
    // First attempt fails on IP1
    mockDNS(['192.0.2.1', '192.0.2.2'], [true, false]);
    browser.load('http://test.site');
    // After STOP + Refresh
    expect(nextAttemptIP).toEqual('192.0.2.2'); // Rotates to working IP
  });
});
Browser Sorting Algorithm Cache Behavior
Chrome Happy Eyeballs v2 (RFC 8305) Prefers last-working IP
Firefox Round-robin with failure tracking Strict TTL adherence
Safari RFC 6724 destination sorting 60s minimum cache

When implementing DNS-based failover:

# Example DNS configuration with proper TTL
example.com.  300  IN  A  192.0.2.1
example.com.  300  IN  A  192.0.2.2
example.com.  300  IN  A  192.0.2.3

Critical findings from real-world testing:

  • Browsers will retry failed IPs after cache expiration (300s in above example)
  • Mobile browsers exhibit more aggressive cache invalidation
  • HTTP/3 implementations show different failover patterns