HTTP client¶
The default¶
With no http.client configured, the bundle discovers a PSR-18 client. If symfony/http-client is installed it is
used and configured with http.timeout (10 seconds by default), max_duration at twice that, and no redirects;
Guzzle gets the equivalent treatment. Any other discovered client keeps its own defaults, including its own timeout,
because the library will not reconfigure a client it did not create.
Redirects are disabled on purpose. An engine endpoint that redirects is a misconfiguration, and following it would hide the real response.
Install the pieces if discovery fails:
composer require symfony/http-client nyholm/psr7
The failure is explicit: "No PSR-18 HTTP client / PSR-17 factories found." It is raised when the transport is first used, not at boot.
Built on first use¶
The transport service is a LazyTransport wrapping a closure. Discovery and client construction happen at the first
outgoing request, so:
- a request that submits nothing pays nothing;
- a
dry_runsetup never builds a client at all; indexnow:checkcan report a missing client as a check error instead of crashing.
Using your own client¶
Point http.client at a service id. Two kinds are accepted:
indexnowkit:
http:
client: 'app.psr18_client' # a Psr\Http\Client\ClientInterface service
indexnowkit:
http:
client: 'my_scoped.client' # a symfony/http-client service, wrapped in Psr18Client automatically
Anything else fails at runtime with "indexnowkit.http.client must be a PSR-18 client or a symfony/http-client service".
A client you supply is used as it is: http.timeout is not applied to it, because its own configuration wins.
Set the timeout on the client instead.
Scoped clients¶
The most useful case is a framework.http_client scoped client, which gives you proxy settings, retries, extra
headers and per-service timeouts without touching the rest of the application.
# config/packages/framework.yaml
framework:
http_client:
scoped_clients:
indexnow.client:
scope: 'https://(api\.indexnow\.org|yandex\.com|www\.bing\.com)'
timeout: 10
max_duration: 20
max_redirects: 0
headers:
Accept: 'application/json'
proxy: '%env(default::HTTP_PROXY)%'
retry_failed:
max_retries: 2
delay: 1000
# config/packages/indexnowkit.yaml
indexnowkit:
http:
client: 'indexnow.client'
Keep max_redirects: 0. And be deliberate about retry_failed: it retries transport-level failures underneath the
library, which then never sees them. That is fine for connection resets, but leave 429 and 5xx to the library so
Retry-After and the Result taxonomy still apply — Symfony's default retry status codes include 429 and 5xx, so
narrow http_codes if you enable it.
Custom endpoints¶
engines accepts full endpoint URLs next to the known names, which is how you point at a staging or mock server:
indexnowkit:
engines: ['https://api.indexnow.org/indexnow']
Custom endpoints must use https, because the key travels in the request body. Plain http is accepted only for
loopback hosts (localhost, 127.0.0.1, [::1]), which is what test suites use.
User-Agent¶
The default is indexnowkit-php/<version> (+https://github.com/indexnowkit/php). Override it with
http.user_agent when an engine or your own proxy needs to identify the traffic. Line breaks are rejected.
Timeouts and what they mean¶
http.timeout is a per-request timeout applied to the client the bundle creates. A timeout surfaces as a failed
result with reason transport, retryable: true, and a warning on the indexnow channel. It is never an
exception in your application.
Ten seconds is generous for an endpoint whose entire job is to accept a JSON list. Lower it if your worker
throughput matters more than the occasional slow acceptance; raise it only if you see transport failures that
disappear on retry.