{"id":21497444,"url":"https://github.com/jetty-project/jetty-reactive-httpclient","last_synced_at":"2025-04-05T00:07:25.563Z","repository":{"id":38375078,"uuid":"100389140","full_name":"jetty-project/jetty-reactive-httpclient","owner":"jetty-project","description":"Jetty ReactiveStreams HttpClient","archived":false,"fork":false,"pushed_at":"2025-03-20T19:01:05.000Z","size":947,"stargazers_count":72,"open_issues_count":8,"forks_count":13,"subscribers_count":14,"default_branch":"4.0.x","last_synced_at":"2025-03-28T23:05:43.604Z","etag":null,"topics":["http","http-client","http2-client","https-client","java","reactive-streams","rxjava"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jetty-project.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","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}},"created_at":"2017-08-15T15:04:22.000Z","updated_at":"2025-03-15T16:54:06.000Z","dependencies_parsed_at":"2023-10-03T00:18:03.247Z","dependency_job_id":"5d831a82-3de0-42db-b3ac-f6674eb8abc3","html_url":"https://github.com/jetty-project/jetty-reactive-httpclient","commit_stats":null,"previous_names":[],"tags_count":71,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jetty-project%2Fjetty-reactive-httpclient","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jetty-project%2Fjetty-reactive-httpclient/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jetty-project%2Fjetty-reactive-httpclient/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jetty-project%2Fjetty-reactive-httpclient/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jetty-project","download_url":"https://codeload.github.com/jetty-project/jetty-reactive-httpclient/tar.gz/refs/heads/4.0.x","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247266563,"owners_count":20910836,"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":["http","http-client","http2-client","https-client","java","reactive-streams","rxjava"],"created_at":"2024-11-23T16:24:02.223Z","updated_at":"2025-04-05T00:07:25.542Z","avatar_url":"https://github.com/jetty-project.png","language":"Java","funding_links":[],"categories":["网络编程"],"sub_categories":["Spring Cloud框架"],"readme":"![GitHub CI](https://github.com/jetty-project/jetty-reactive-httpclient/workflows/GitHub%20CI/badge.svg)\n\n# Jetty ReactiveStream HttpClient\n\nA [ReactiveStreams](http://www.reactive-streams.org/) wrapper around [Jetty](https://eclipse.dev/jetty)'s [HttpClient](https://www.eclipse.dev/jetty/documentation/jetty-12/programming-guide/index.html#pg-client-http).\n\n## Versions\n\n| Jetty ReactiveStream HttpClient Versions | Min Java Version | Jetty Version | Status                                     |\n|------------------------------------------|------------------|---------------|--------------------------------------------|\n| `4.0.x`                                  | Java 17          | Jetty 12.0.x  | Stable                                     |\n| `3.0.x`                                  | Java 11          | Jetty 11.0.x  | End of Community Support (see [#461](https://github.com/jetty-project/jetty-reactive-httpclient/issues/461)) |\n| `2.0.x`                                  | Java 11          | Jetty 10.0.x  | End of Community Support (see [#461](https://github.com/jetty-project/jetty-reactive-httpclient/issues/461)) |\n| `1.1.x`                                  | Java 8           | Jetty 9.4.x   | End of Community Support (see [#153](https://github.com/jetty-project/jetty-reactive-httpclient/issues/153)) |\n\n## Usage\n\n### Plain ReactiveStreams Usage\n\n```java\n// Create and start Jetty's HttpClient.\nHttpClient httpClient = new HttpClient();\nhttpClient.start();\n\n// Create a request using the HttpClient APIs.\nRequest request = httpClient.newRequest(\"http://localhost:8080/path\");\n\n// Wrap the request using the API provided by this project.\nReactiveRequest reactiveRequest = ReactiveRequest.newBuilder(request).build();\n\n// Obtain a ReactiveStream Publisher for the response, discarding the response content.\nPublisher\u003cReactiveResponse\u003e publisher = reactiveRequest.response(ReactiveResponse.Content.discard());\n\n// Subscribe to the Publisher to send the request.\npublisher.subscribe(new Subscriber\u003cReactiveResponse\u003e() {\n    @Override\n    public void onSubscribe(Subscription subscription) {\n        // This is where the request is actually sent.\n        subscription.request(1);\n    }\n\n    @Override\n    public void onNext(ReactiveResponse response) {\n        // Use the response\n    }\n\n    @Override\n    public void onError(Throwable failure) {\n    }\n\n    @Override\n    public void onComplete() {\n    }\n});\n```\n\n### RxJava 3 Usage\n\n```java\n// Create and start Jetty's HttpClient.\nHttpClient httpClient = new HttpClient();\nhttpClient.start();\n\n// Create a request using the HttpClient APIs.\nRequest request = httpClient.newRequest(\"http://localhost:8080/path\");\n\n// Wrap the request using the API provided by this project.\nReactiveRequest reactiveRequest = ReactiveRequest.newBuilder(request).build();\n\n// Obtain a ReactiveStreams Publisher for the response, discarding the response content.\nPublisher\u003cReactiveResponse\u003e publisher = reactiveRequest.response(ReactiveResponse.Content.discard());\n\n// Wrap the ReactiveStreams Publisher with RxJava.\nint status = Single.fromPublisher(publisher)\n        .map(ReactiveResponse::getStatus)\n        .blockingGet();\n```\n\n### Response Content Processing\n\nThe response content is processed by passing a `BiFunction` to `ReactiveRequest.response()`.\n\nThe `BiFunction` takes as parameters the `ReactiveResponse` and a `Publisher` for the response content, and must return a `Publisher` of items of type `T` that is the result of the response content processing.\n\nBuilt-in utility functions can be found in `ReactiveResponse.Content`.\n\n#### Example: discarding the response content\n\n```java\nPublisher\u003cReactiveResponse\u003e response = request.response(ReactiveResponse.Content.discard());\n```\n\n#### Example: converting the response content to a String\n\n```java\nPublisher\u003cString\u003e string = request.response(ReactiveResponse.Content.asString());\n```\n\n#### Example: discarding non 200 OK response content\n\n```java\nPublisher\u003cReactiveResponse.Result\u003cString\u003e\u003e publisher = request.response((response, content) -\u003e {\n    if (response.getStatus() == HttpStatus.OK_200) {\n        return ReactiveResponse.Content.asStringResult().apply(response, content);\n    } else {\n        return ReactiveResponse.Content.\u003cString\u003easDiscardResult().apply(response, content);\n    }\n});\n```\n\nClass `ReactiveResponse.Result` is a Java `record` that holds the response and the response content to allow application code to implement logic that uses both response information such as response status code and response headers, and response content information.\n\nAlternatively, you can write your own processing `BiFunction` using any ReactiveStreams library, such as RxJava 3 (which provides class `Flowable`):\n\n#### Example: discarding non 200 OK response content\n\n```java\nPublisher\u003cContent.Chunk\u003e publisher = reactiveRequest.response((reactiveResponse, contentPublisher) -\u003e {\n    if (reactiveResponse.getStatus() == HttpStatus.OK_200) {\n        // Return the response content itself.\n        return contentPublisher;\n    } else {\n        // Discard the response content.\n        return Flowable.fromPublisher(contentPublisher)\n                .filter(chunk -\u003e {\n                    // Tell HttpClient that you are done with this chunk.\n                    chunk.release();\n                    // Discard this chunk.\n                    return false;\n                });\n    }\n});\n```\n\nThe response content (if any) can be further processed:\n\n```java\nSingle\u003cLong\u003e contentLength = Flowable.fromPublisher(publisher)\n        .map(chunk -\u003e {\n            // Tell HttpClient that you are done with this chunk.\n            chunk.release();\n            // Return the number of bytes of this chunk.\n            return chunk.remaining();\n        })\n        // Sum the bytes of the chunks.\n        .reduce(0L, Long::sum);\n```\n\n### Providing Request Content\n\nRequest content can be provided in a ReactiveStreams way, through the `ReactiveRequest.Content` class, which _is-a_ `Publisher` with the additional specification of the content length and the content type.\n\nBelow you can find an example using the utility methods in `ReactiveRequest.Content` to create request content from a String:\n\n```java\nHttpClient httpClient = ...;\n\nString text = \"content\";\nReactiveRequest request = ReactiveRequest.newBuilder(httpClient, \"http://localhost:8080/path\")\n        .content(ReactiveRequest.Content.fromString(text, \"text/plain\", StandardCharsets.UTF_8))\n        .build();\n```\n\nBelow another example of creating request content from another `Publisher`:\n\n```java\nHttpClient httpClient = ...;\n\n// The Publisher of request content.\nPublisher\u003cT\u003e publisher = ...;\n\n// Transform items of type T into ByteBuffer chunks.\nCharset charset = StandardCharsets.UTF_8;\nFlowable\u003cContent.Chunk\u003e chunks = Flowable.fromPublisher(publisher)\n        .map((T t) -\u003e toJSON(t))\n        .map((String json) -\u003e json.getBytes(charset))\n        .map((byte[] bytes) -\u003e ByteBuffer.wrap(bytes))\n        .map(byteBuffer -\u003e Content.Chunk.from(byteBuffer, false));\n\nReactiveRequest request = ReactiveRequest.newBuilder(httpClient, \"http://localhost:8080/path\")\n        .content(ReactiveRequest.Content.fromPublisher(chunks, \"application/json\", charset))\n        .build();\n```\n\n### Events\n\nIf you are interested in the request and/or response events that are emitted by the Jetty HttpClient APIs, you can obtain a `Publisher` for request and/or response events, and subscribe a listener to be notified of the events.\n\nThe event `Publisher`s are \"hot\" producers and do no buffer events.\n\nIf you subscribe to an event `Publisher` after the events have started, the `Subscriber` will not be notified of events that already happened, and will be notified of any event that will happen.\n\n```java\nHttpClient httpClient = ...;\n\nReactiveRequest request = ReactiveRequest.newBuilder(httpClient, \"http://localhost:8080/path\").build();\nPublisher\u003cReactiveRequest.Event\u003e requestEvents = request.requestEvents();\n\n// Subscribe to the request events before sending the request.\nrequestEvents.subscribe(new Subscriber\u003cReactiveRequest.Event\u003e() {\n    ...\n});\n\n// Similarly for response events.\nPublisher\u003cReactiveResponse.Event\u003e responseEvents = request.responseEvents();\n\n// Subscribe to the response events before sending the request.\nresponseEvents.subscribe(new Subscriber\u003cReactiveResponse.Event\u003e() {\n    ...\n});\n\n// Send the request.\nReactiveResponse response = Single.fromPublisher(request.response(ReactiveResponse.Content.discard()))\n        .blockingGet();\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjetty-project%2Fjetty-reactive-httpclient","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjetty-project%2Fjetty-reactive-httpclient","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjetty-project%2Fjetty-reactive-httpclient/lists"}