http advanced

How to make asynchronous HTTP requests in Perl?

Question

How to make asynchronous HTTP requests in Perl?

How to Make Asynchronous HTTP Requests in Perl Without External Modules

Performing asynchronous HTTP requests in Perl usually involves event-driven modules like Mojo::UserAgent or AnyEvent::HTTP. However, these modules are not part of the Perl core and require installation. In strictly sandboxed environments where CPAN modules and network access are not allowed, true asynchronous HTTP requests cannot be performed in the usual sense.

That said, you can simulate concurrency using Perl's built-in fork or select for non-blocking socket I/O, but this typically requires manual socket handling and is complex for HTTP clients.

Without external modules, the simplest approach is to do synchronous HTTP requests using core modules like LWP::Simple or raw IO::Socket::INET, but these block until each request finishes. There’s no baked-in non-blocking HTTP client in core Perl.

Example: Simulated "Asynchronous" HTTP Requests with fork()

This minimal example uses fork to make two HTTP GET requests concurrently by spawning child processes that each perform their own blocking request. Results are printed asynchronously as they complete. This approach avoids external modules but still requires network access.


use strict;
use warnings;
use feature 'say';
use IO::Socket::INET;

sub fetch_http {
    my ($host, $path) = @_;

    # Simple HTTP/1.0 GET request using bare TCP socket
    my $sock = IO::Socket::INET->new(
        PeerAddr => $host,
        PeerPort => 80,
        Proto    => 'tcp',
        Timeout  => 5,
    ) or do {
        say "Failed to connect to $host: $@";
        return;
    };

    print $sock "GET $path HTTP/1.0\r\nHost: $host\r\nConnection: close\r\n\r\n";

    my $response = '';
    while (<$sock>) {
        $response .= $_;
    }
    close $sock;

    # Extract status line and content length
    if ($response =~ m{^HTTP/\d\.\d\s+(\d+)}m) {
        my $status = $1;
        my ($body) = $response =~ /\r\n\r\n(.*)/s;
        my $length = length $body // 0;
        say "Host: $host$path - Status: $status, Content length: $length bytes";
    } else {
        say "Host: $host$path - Invalid HTTP response.";
    }
}

my @requests = (
    ['httpbin.org', '/get'],
    ['example.com', '/'],
);

my @kids;

for my $req (@requests) {
    my $pid = fork();
    if (!defined $pid) {
        warn "Can't fork: $!";
        next;
    }
    if ($pid == 0) {
        # Child process does the fetch
        fetch_http(@$req);
        exit 0;
    } else {
        push @kids, $pid;
    }
}

# Parent waits for children to finish
for my $kid (@kids) {
    waitpid($kid, 0);
}

say "All requests completed.";

Explanation

  • fork duplicates the current process; child processes do blocking HTTP requests independently.
  • IO::Socket::INET (core module) makes a TCP connection to the host on port 80.
  • A simple raw HTTP GET request is sent; response is read fully.
  • Status code and content length are parsed from the response manually.
  • The parent process waits for all children to complete before printing final message.
  • This simulates async requests without complicated event loops or external modules.

Common Pitfalls

  • Missing SSL support: This example only works with plain HTTP on port 80, not HTTPS.
  • Limited error handling: Socket connect failures or malformed responses produce warnings but continue.
  • Fork availability: This approach requires a Unix-like system supporting fork; not available on all platforms (e.g., Windows).
  • Not truly non-blocking: Each child blocks on its own request, but multiple processes run concurrently from the parent perspective.

Summary

Without external modules or network libraries, true asynchronous HTTP requests are difficult in pure Perl. Using fork to parallelize blocking requests is a simple workaround if you have OS support for it. For real non-blocking async HTTP, modules like Mojo::UserAgent or AnyEvent::HTTP are recommended but require installation and network access.

Verified Code

Executed in a sandbox to capture real output. • v5.34.1 • 1807ms

Tip: edit code and use “Run (Browser)”. Server runs always execute the published, verified snippet.
STDOUT
Host: example.com/ - Status: 200, Content length: 513 bytes
Host: httpbin.org/get - Status: 200, Content length: 199 bytes
All requests completed.
STDERR
(empty)

Was this helpful?

Related Questions