{"id":13721026,"url":"https://github.com/amphp/http-client","last_synced_at":"2025-05-14T19:07:45.979Z","repository":{"id":403451,"uuid":"3445729","full_name":"amphp/http-client","owner":"amphp","description":"An advanced async HTTP client library for PHP, enabling efficient, non-blocking, and concurrent requests and responses.","archived":false,"fork":false,"pushed_at":"2025-04-30T03:01:47.000Z","size":4943,"stargazers_count":714,"open_issues_count":14,"forks_count":70,"subscribers_count":30,"default_branch":"5.x","last_synced_at":"2025-04-30T03:35:05.665Z","etag":null,"topics":["amphp","async","http","http-client","https","php","revolt"],"latest_commit_sha":null,"homepage":"https://amphp.org/http-client","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/amphp.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"amphp"}},"created_at":"2012-02-15T01:30:19.000Z","updated_at":"2025-04-30T02:58:23.000Z","dependencies_parsed_at":"2023-12-16T00:52:39.203Z","dependency_job_id":"639ead42-6488-483c-9a76-4f591fa6a332","html_url":"https://github.com/amphp/http-client","commit_stats":{"total_commits":1549,"total_committers":47,"mean_commits":32.95744680851064,"dds":0.6120077469335055,"last_synced_commit":"0fd30c4ff2231b044ead0e7a5d3aedafcbca59b1"},"previous_names":[],"tags_count":115,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amphp%2Fhttp-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amphp%2Fhttp-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amphp%2Fhttp-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amphp%2Fhttp-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/amphp","download_url":"https://codeload.github.com/amphp/http-client/tar.gz/refs/heads/5.x","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254209859,"owners_count":22032897,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["amphp","async","http","http-client","https","php","revolt"],"created_at":"2024-08-03T01:01:11.496Z","updated_at":"2025-05-14T19:07:44.306Z","avatar_url":"https://github.com/amphp.png","language":"PHP","readme":"# amphp/http-client\n\nAMPHP is a collection of event-driven libraries for PHP designed with fibers and concurrency in mind.\nThis package provides an asynchronous HTTP client for PHP based on [Revolt](https://revolt.run/).\nIts API simplifies standards-compliant HTTP resource traversal and RESTful web service consumption without obscuring the underlying protocol.\nThe library manually implements HTTP over TCP sockets; as such it has no dependency on `ext/curl`.\n\n## Features\n\n - Supports HTTP/1 and HTTP/2\n - [Requests concurrently by default](examples/concurrency/1-concurrent-fetch.php)\n - [Pools persistent connections (keep-alive @ HTTP/1.1, multiplexing @ HTTP/2)](examples/pooling/1-connection-count.php)\n - [Transparently follows redirects](#redirects)\n - [Decodes compressed entity bodies (gzip, deflate)](examples/basic/7-gzip.php)\n - [Exposes headers and message data](examples/basic/1-get-request.php)\n - [Streams entity bodies for memory management with large transfers](examples/streaming/1-large-response.php)\n - [Supports all standard and custom HTTP method verbs](#request-method)\n - [Simplifies HTTP form submissions](examples/basic/4-forms.php)\n - [Implements secure-by-default TLS (`https://`)](examples/basic/1-get-request.php)\n - [Supports cookies and sessions](#cookies)\n - [Functions seamlessly behind HTTP proxies](#proxies)\n\n## Installation\n\nThis package can be installed as a [Composer](https://getcomposer.org/) dependency.\n\n```bash\ncomposer require amphp/http-client\n```\n\nAdditionally, you might want to install the `nghttp2` library to take advantage of FFI to speed up and reduce the memory usage.\n\n## Usage\n\nThe main interaction point with this library is the `HttpClient` class.\n`HttpClient` instances can be built using `HttpClientBuilder` without knowing about the existing implementations.\n\n`HttpClientBuilder` allows to register two kinds of [interceptors](#interceptors), which allows customizing the `HttpClient` behavior in a composable fashion.\n\nIn its simplest form, the HTTP client takes a request with a URL as string and interprets that as a `GET` request to that resource without any custom headers.\nStandard headers like `Accept`, `Connection` or `Host` will automatically be added if not present.\n\n```php\nuse Amp\\Http\\Client\\HttpClientBuilder;\n\n$client = HttpClientBuilder::buildDefault();\n\n$response = $client-\u003erequest(new Request(\"https://httpbin.org/get\"));\n\nvar_dump($response-\u003egetStatus());\nvar_dump($response-\u003egetHeaders());\nvar_dump($response-\u003egetBody()-\u003ebuffer());\n```\n\n### Request\n\nThe `HttpClient` requires a `Request` being passed as first argument to `request()`.\nThe `Request` class can be used to specify further specifics of the request such as setting headers or changing the request method.\n\n\u003e **Note**\n\u003e `Request` objects are mutable (instead of immutable as in `amphp/artax` / PSR-7).\n\u003e\n\u003e Cloning `Request` objects will result in a deep clone, but doing so is usually only required if requests are retried or cloned for sub-requests.\n\n#### Request URI\n\nThe constructor requires an absolute request URI. `Request::setUri(string $uri)` allows changing the request URI.\n\n```php\n$request = new Request(\"https://httpbin.org/post\", \"POST\");\n$request-\u003esetBody(\"foobar\");\n$request-\u003esetUri(\"https://google.com/\");\n```\n\n`Request::getUri()` exposes the request URI of the given `Request` object.\n\n#### Request Method\n\nThe constructor accepts an optional request method, it defaults to `GET`. `Request::setMethod(string $method)` allows changing the request method.\n\n```php\n$request = new Request(\"https://httpbin.org/post\", \"POST\");\n$request-\u003esetBody(\"foobar\");\n$request-\u003esetMethod(\"PUT\");\n```\n\n`Request::getMethod()` exposes the request method of the given `Request` object.\n\n#### Request Headers\n\n`Request::setHeader(string $field, string $value)` allows changing the request headers. It will remove any previous values for that field. `Request::addHeader(string $field, string $value)` allows adding an additional header line without removing existing lines.\n\n`Request::setHeaders(array $headers)` allows adding multiple headers at once with the array keys being the field names and the values being the header values. The header values can also be arrays of strings to set multiple header lines.\n\n`Request::hasHeader(string $field)` checks whether at least one header line with the given name exists.\n\n`Request::getHeader(string $field)` returns the first header line with the given name or `null` if no such header exists.\n\n`Request::getHeaderArray(string $field)` returns an array of header lines with the given name. An empty array is returned if no header with the given name exists.\n\n`Request::getHeaders()` returns an associative array with the keys being the header names and the values being arrays of header lines.\n\n```php\n$request = new Request(\"https://httpbin.org/post\", \"POST\");\n$request-\u003esetHeader(\"X-Foobar\", \"Hello World\");\n$request-\u003esetBody(\"foobar\");\n```\n\n#### Request Bodies\n\n`Request::setBody($body)` allows changing the request body. Accepted types are `string`, `null`, and `HttpContent`. `string` and `null` are automatically converted to an instance of `HttpContent`.\n\n\u003e **Note**\n\u003e `HttpContent` is basically a factory for request bodies. We cannot simply accept streams here, because a request body might have to be sent again on a redirect / retry.\n\n```php\n$request = new Request(\"https://httpbin.org/post\", \"POST\");\n$request-\u003esetBody(\"foobar\");\n```\n\n`Request::getBody()` exposes the request body of the given `Request` object and will always return a `HttpContent`.\n\n### Response\n\n`HttpClient::request()` returns a `Response` as soon as the response headers are successfully received.\n\n\u003e **Note**\n\u003e `Response` objects are mutable (instead of immutable as in Artax v3 / PSR-7)\n\n#### Response Status\n\nYou can retrieve the response's HTTP status using `getStatus()`. It returns the status as an integer. The optional (and possibly empty) reason associated with the status can be retrieved using `getReason()`.\n\n```php\n$response = $client-\u003erequest($request);\n\nvar_dump($response-\u003egetStatus(), $response-\u003egetReason());\n```\n\n#### Response Protocol Version\n\nYou can retrieve the response's HTTP protocol version using `getProtocolVersion()`.\n\n```php\n$response = $client-\u003erequest($request);\n\nvar_dump($response-\u003egetProtocolVersion());\n```\n\n#### Response Headers\n\nResponse headers can be accessed by a set of methods.\n\n* `hasHeader(string)` returns whether a given header is present.\n* `getHeader(string)` returns the first header with the given name or `null` if no such header is present.\n* `getHeaderArray(string)` returns all headers with the given name, possibly an empty array.\n* `getHeaders()` returns all headers as an associative array, see below.\n\n**`getHeaders()` Format**\n\n```php\n[\n    \"header-1\" =\u003e [\n        \"value-1\",\n        \"value-2\",\n    ],\n    \"header-2\" =\u003e [\n        \"value-1\",\n    ],\n]\n```\n\n#### Response Body\n\n`getBody()` returns a [`Payload`](https://v3.amphp.org/byte-stream#payload), which allows simple buffering and streaming access.\n\n\u003e **Warning**\n\u003e `$chunk = $response-\u003egetBody()-\u003eread();` reads only a single chunk from the body while `$contents = $response-\u003egetBody()-\u003ebuffer()` buffers the complete body.\n\u003e Please refer to the [`Payload` documentation](https://v3.amphp.org/byte-stream#payload) for more information.\n\n#### Request, Original Request and Previous Response\n\n`getRequest()` allows access to the request corresponding to the response. This might not be the original request in case of redirects. `getOriginalRequest()` returns the original request sent by the client. This might not be the same request that was passed to `Client::request()`, because the client might normalize headers or assign cookies. `getPreviousResponse` allows access to previous responses in case of redirects, but the response bodies of these responses won't be available, as they're discarded. If you need access to these, you need to disable auto redirects and implement them yourself.\n\n### Interceptors\n\nInterceptors allow customizing the `HttpClient` behavior in a composable fashion.\nUse cases range from adding / removing headers from a request / response and recording timing information to more advanced use cases like a fully compliant [HTTP cache](https://github.com/amphp/http-client-cache) that intercepts requests and serves them from the cache if possible.\n\n```php\nuse Amp\\Http\\Client\\Client;\nuse Amp\\Http\\Client\\HttpClientBuilder;\nuse Amp\\Http\\Client\\Interceptor\\SetRequestHeader;\nuse Amp\\Http\\Client\\Interceptor\\SetResponseHeader;\nuse Amp\\Http\\Client\\Request;\n\n$client = (new HttpClientBuilder)\n    -\u003eintercept(new SetRequestHeader('x-foo', 'bar'))\n    -\u003eintercept(new SetResponseHeader('x-tea', 'now'))\n    -\u003ebuild();\n\n$response = $client-\u003erequest(new Request(\"https://httpbin.org/get\"));\n$body = $response-\u003egetBody()-\u003ebuffer();\n```\n\nThere are two kinds of interceptors with separate interfaces named `ApplicationInterceptor` and `NetworkInterceptor`.\n\n#### Choosing the right interceptor\n\nMost interceptors should be implemented as `ApplicationInterceptor`.\nHowever, there's sometimes the need to have access to the underlying connection properties.\nIn such a case, a `NetworkInterceptor` can be implemented to access the used IPs and TLS settings.\n\nAnother use-case for implementing a `NetworkInterceptor` is an interceptor, that should only ever run if the request is sent over the network instead of served from a cache or similar.\nHowever, that should usually be solved with the configuration order of the application interceptors.\n\nThe big disadvantage of network interceptors is that they have to be rather quick and can't take too long, because they're only invoked after the connection has been created and the client will run into a timeout if there's no activity within a reasonable time.\n\n#### List of Interceptors\n\n- `AddRequestHeader`\n- `AddResponseHeader`\n- `ConditionalInterceptor`\n- `DecompressResponse`\n- `FollowRedirects`\n- `ForbidUriUserInfo`\n- `IfOrigin`\n- `ModifyRequest`\n- `ModifyResponse`\n- `RemoveRequestHeader`\n- `RemoveResponseHeader`\n- `RetryRequests`\n- `SetRequestHeader`\n- `SetRequestHeaderIfUnset`\n- `SetResponseHeader`\n- `SetResponseHeaderIfUnset`\n- `SetRequestTimeout`\n- [`CookieHandler`](https://github.com/amphp/http-client-cookies)\n- [`PrivateCache`](https://github.com/amphp/http-client-cache)\n\n### Redirects\n\nIf you use `HttpClientBuilder`, the resulting `HttpClient` will automatically follow up to ten redirects by default.\nAutomatic following can be customized or disabled (using a limit of `0`) using `HttpClientBuilder::followRedirects()`.\n\n#### Redirect Policy\n\nThe `FollowRedirects` interceptor will only follow redirects with a `GET` method.\nIf another request method is used and a `307` or `308` response is received, the response will be returned as is, so another interceptor or the application can take care of it.\nCross-origin redirects will be attempted without any headers set, so any application headers will be discarded.\nIf `HttpClientBuilder` is used to configure the client, the `FollowRedirects` interceptor is the outermost interceptor, so any headers set by interceptors will still be present in the response.\nIt is therefore recommended to set headers via interceptors instead of directly in the request.\n\n#### Examining the Redirect Chain\n\nAll previous responses can be accessed from the resulting `Response` via `Response::getPreviousResponse()`.\nHowever, the response body is discarded on redirects, so it can no longer be consumed.\nIf you want to consume redirect response bodies, you need to implement your own interceptor.\n\n### Cookies\n\nSee [`amphp/http-client-cookies`](https://github.com/amphp/http-client-cookies).\n\n### Logging\n\nThe `LogHttpArchive` event listener allows logging all requests / responses including detailed timing information to an [HTTP archive (HAR)](https://en.wikipedia.org/wiki/HAR_%28file_format%29).\n\nThese log files can then be imported into the browsers developer tools or online tools like [HTTP Archive Viewer](http://www.softwareishard.com/har/viewer/) or [Google's HAR Analyzer](https://toolbox.googleapps.com/apps/har_analyzer/).\n\n\u003e **Warning**\n\u003e Be careful if your log files might contain sensitive information in URLs or headers if you submit these files to third parties like the linked services above.\n\n```php\nuse Amp\\Http\\Client\\HttpClientBuilder;\nuse Amp\\Http\\Client\\EventListener\\LogHttpArchive;\n\n$httpClient = (new HttpClientBuilder)\n    -\u003elisten(new LogHttpArchive('/tmp/http-client.har'))\n    -\u003ebuild();\n\n$httpClient-\u003erequest(...);\n```\n\n![HAR Viewer Screenshot](https://user-images.githubusercontent.com/2743004/196048526-bf496986-ea5b-4a30-9b3f-4fa51a9c5bb1.png)\n\n### Proxies\n\nSee [`amphp/http-tunnel`](https://github.com/amphp/http-tunnel).\n\n## Versioning\n\n`amphp/http-client` follows the [semver](http://semver.org/) semantic versioning specification like all other `amphp` packages.\n\nEverything in an `Internal` namespace or marked as `@internal` is not public API and therefore not covered by BC guarantees.\n\n## Security\n\nIf you discover any security related issues, please email [`me@kelunik.com`](mailto:me@kelunik.com) instead of using the issue tracker.\n\n## License\n\nThe MIT License (MIT). Please see [`LICENSE`](./LICENSE) for more information.\n","funding_links":["https://github.com/sponsors/amphp"],"categories":["HTTP","PHP","类库","Programming Languages"],"sub_categories":["Client","HTTP/网络通信","PHP"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famphp%2Fhttp-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Famphp%2Fhttp-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famphp%2Fhttp-client/lists"}