📖
【PHP】AMPHP で HTTP/2 対応のサーバーをつくる
Composer でインストールする
composer require amphp/http-server
HTTP/2 ヘッダー圧縮の仕様である HPACk のために nghttp2 を導入した。nghttp2 はオプションでなくても PHP ネイティブのクラス (Amp\Http\Internal\HPackNative
) がある。Debian の場合、次のコマンドを実行する
sudo apt install libnghttp2-dev
server.php
// https://github.com/amphp/http-server/blob/3.x/examples/hello-world.php
<?php
require __DIR__ . "/vendor/autoload.php";
use Amp\ByteStream;
use Amp\Http\HttpStatus;
use Amp\Http\Server\DefaultErrorHandler;
use Amp\Http\Server\Driver\SocketClientFactory;
use Amp\Http\Server\Request;
use Amp\Http\Server\RequestHandler;
use Amp\Http\Server\Response;
use Amp\Http\Server\SocketHttpServer;
use Amp\Log\ConsoleFormatter;
use Amp\Log\StreamHandler;
use Amp\Socket;
use Monolog\Logger;
use Monolog\Processor\PsrLogMessageProcessor;
use function Amp\trapSignal;
// Run this script, then visit http://localhost:1337/ or https://localhost:1338/ in your browser.
$cert = new Socket\Certificate(
__DIR__ . '/localhost.pem',
__DIR__ . '/localhost-key.pem'
);
$context = (new Socket\BindContext)
->withTlsContext((new Socket\ServerTlsContext)
->withDefaultCertificate($cert));
$logHandler = new StreamHandler(ByteStream\getStdout());
$logHandler->pushProcessor(new PsrLogMessageProcessor());
$logHandler->setFormatter(new ConsoleFormatter());
$logger = new Logger('server');
$logger->pushHandler($logHandler);
$logger->useLoggingLoopDetection(false);
$server = new SocketHttpServer(
$logger,
new Socket\ResourceServerSocketFactory(),
new SocketClientFactory($logger),
);
$server->expose("0.0.0.0:1337");
$server->expose("[::]:1337");
$server->expose("0.0.0.0:1338", $context);
$server->expose("[::]:1338", $context);
$server->start(new class implements RequestHandler {
public function handleRequest(Request $request): Response
{
return new Response(
status: HttpStatus::OK,
headers: ["content-type" => "text/plain; charset=utf-8"],
body: "Hello, World!",
);
}
}, new DefaultErrorHandler());
// Await a termination signal to be received.
$signal = trapSignal([\SIGHUP, \SIGINT, \SIGQUIT, \SIGTERM]);
$logger->info(sprintf("Received signal %d, stopping HTTP server", $signal));
$server->stop();
自己署名の証明書と鍵は mkcert で生成する
mkcert localhost
HTTP サーバーを起動させる
php server.php
curl でリクエストを送信すると HTTP/2 が利用できることがわかる
curl -v https://localhost:1338
* Trying 127.0.0.1:1338...
* Connected to localhost (127.0.0.1) port 1338 (#0)
* ALPN: offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN: server accepted h2
* Server certificate:
* subject: O=mkcert development certificate; OU=masakielastic@penguin
* start date: Jun 29 19:38:12 2024 GMT
* expire date: Sep 29 19:38:12 2026 GMT
* subjectAltName: host "localhost" matched cert's "localhost"
* issuer: O=mkcert development CA; OU=masakielastic@penguin; CN=mkcert masakielastic@penguin
* SSL certificate verify ok.
* using HTTP/2
* h2h3 [:method: GET]
* h2h3 [:path: /]
* h2h3 [:scheme: https]
* h2h3 [:authority: localhost:1338]
* h2h3 [user-agent: curl/7.88.1]
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x55a209446c80)
> GET / HTTP/2
> Host: localhost:1338
> user-agent: curl/7.88.1
> accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
< HTTP/2 200
< content-type: text/plain; charset=utf-8
< date: Sat, 29 Jun 2024 20:08:57 GMT
<
* Connection #0 to host localhost left intact
Hello, World!
Discussion