{"id":214,"date":"2023-01-23T23:48:13","date_gmt":"2023-01-23T14:48:13","guid":{"rendered":"https:\/\/hirabay.net\/?p=214"},"modified":"2023-01-30T19:52:40","modified_gmt":"2023-01-30T10:52:40","slug":"%e3%80%90webclient%e3%80%91%e3%82%b3%e3%83%94%e3%83%9a%e3%81%a7%e4%bd%bf%e3%81%88%e3%82%8b%e5%ae%9f%e8%a3%85%e9%9b%86","status":"publish","type":"post","link":"https:\/\/hirabay.net\/?p=214","title":{"rendered":"\u3010WebClient\u3011\u30b3\u30d4\u30da\u3067\u4f7f\u3048\u308b\u5b9f\u88c5\u96c6"},"content":{"rendered":"\n<p>WebClient\u3092\u4f7f\u3063\u305f\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u672c\u756a\u904b\u7528\u3059\u308b\u305f\u3081\u306b\u610f\u8b58\u3057\u3066\u304a\u304d\u305f\u3044\u8a2d\u5b9a\u3068\u305d\u306e\u8a2d\u5b9a\u65b9\u6cd5\u3092\u307e\u3068\u3081\u3066\u307f\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<p>\u81ea\u5206\u306e\u73fe\u5834\u3067\u610f\u8b58\u3057\u3066\u3044\u308b\u3053\u3068\u304c\u4e2d\u5fc3\u306b\u306a\u308a\u307e\u3059\u304c\u3001\u30b3\u30d4\u30da\u3067\u305d\u306e\u307e\u307e\u672c\u756a\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306b\u4f7f\u3046\u3088\u3046\u306a\u30b3\u30fc\u30c9\u3092\u6b8b\u3057\u3066\u304a\u304d\u307e\u3059\uff01<\/p>\n\n\n\n<div class=\"toc\"><br \/>\n<b>Warning<\/b>:  Undefined array key \"is_admin\" in <b>\/home\/c4179872\/public_html\/hirabay.net\/wp-content\/themes\/sango-theme\/library\/gutenberg\/dist\/classes\/Toc.php<\/b> on line <b>110<\/b><br \/>\n<br \/>\n<b>Warning<\/b>:  Undefined array key \"is_category_top\" in <b>\/home\/c4179872\/public_html\/hirabay.net\/wp-content\/themes\/sango-theme\/library\/gutenberg\/dist\/classes\/Toc.php<\/b> on line <b>115<\/b><br \/>\n<br \/>\n<b>Warning<\/b>:  Undefined array key \"is_top\" in <b>\/home\/c4179872\/public_html\/hirabay.net\/wp-content\/themes\/sango-theme\/library\/gutenberg\/dist\/classes\/Toc.php<\/b> on line <b>122<\/b><br \/>\n    <div id=\"toc_container\" class=\"sgb-toc--bullets js-smooth-scroll\">\n      <p class=\"toc_title\">\u76ee\u6b21 <\/p>\n      <ul class=\"toc_list\">\n  <li class=\"first\">\n    <a href=\"#i-0\">\u4f9d\u5b58\u30e9\u30a4\u30d6\u30e9\u30ea<\/a>\n  <\/li>\n  <li>\n    <a href=\"#i-1\">\u5171\u901a\u306e\u8a2d\u5b9a<\/a>\n  <\/li>\n  <li>\n    <a href=\"#i-2\">URL\u3078\u306e\u5909\u6570\u306e\u57cb\u3081\u8fbc\u307f<\/a>\n  <\/li>\n  <li>\n    <a href=\"#i-3\">keepalive\u306e\u7121\u52b9\u5316<\/a>\n  <\/li>\n  <li>\n    <a href=\"#i-4\">Proxy\u30d8\u30c3\u30c0<\/a>\n  <\/li>\n  <li class=\"last\">\n    <a href=\"#i-5\">\u5358\u4f53\u30c6\u30b9\u30c8<\/a>\n  <\/li>\n<\/ul>\n\n      \n    <\/div><\/div><h2 class=\"wp-block-heading\" id=\"i-0\">\u4f9d\u5b58\u30e9\u30a4\u30d6\u30e9\u30ea<\/h2>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism undefined-numbers lang-groovy\" data-file=\"build.gradle\" data-lang=\"Groovy\"><code>implementation 'org.springframework.boot:spring-boot-starter-webflux:2.5.0'<\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-1\"><br>\u5171\u901a\u306e\u8a2d\u5b9a<\/h2>\n\n\n\n<p>\u3042\u308b\u7a0b\u5ea6\u5171\u901a\u3067\u5b9f\u88c5\u3059\u308b\u3067\u3042\u308d\u3046\u8a2d\u5b9a\u3092\u307e\u3068\u3081\u3066\u304a\u304d\u307e\u3059<\/p>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism undefined-numbers lang-java\" data-lang=\"Java\"><code>    @Bean\n    public WebClient webClient(MetricsWebClientCustomizer metricsWebClientCustomizer) {\n        var connectionProvider = ConnectionProvider.builder(\"sample\")\n                .maxConnections(100) \/\/ \u30b3\u30cd\u30af\u30b7\u30e7\u30f3\u30d7\u30fc\u30eb\u6570\n                .maxIdleTime(Duration.ofSeconds(59))  \/\/ keep alive\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\n                .metrics(true) \/\/ \u30b3\u30cd\u30af\u30b7\u30e7\u30f3\u6570\u306e\u30e1\u30c8\u30ea\u30af\u30b9\u3092\u6709\u52b9\u5316\n                .build();\n\n        var httpClient = HttpClient.create(connectionProvider)\n                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1_000) \/\/ connection timeout\n                .responseTimeout(Duration.ofMillis(500)); \/\/ read timeout\n\n        return WebClient.builder()\n                .clientConnector(new ReactorClientHttpConnector(httpClient))\n                .baseUrl(\"http:\/\/localhost:8080\")\n                .apply(metricsWebClientCustomizer::customize)  \/\/ http client\u306e\u30e1\u30c8\u30ea\u30af\u30b9\u3092\u53ce\u96c6\n                .build();\n    }<\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-2\">URL\u3078\u306e\u5909\u6570\u306e\u57cb\u3081\u8fbc\u307f<\/h2>\n\n\n\n<p>\u53ef\u5909\u306a\u90e8\u5206\u306f\u30af\u30a8\u30ea\u30d1\u30e9\u30e1\u30fc\u30bf\u3082\u542b\u3081\u3066uri\u306e\u7b2c\u4e8c\u5f15\u6570\u4ee5\u964d\u3067\u6307\u5b9a\u3057\u306a\u3044\u3068\u30c0\u30e1\u3002<br>\u53ef\u5909\u306aURL\u3092\u305d\u306e\u307e\u307e\u6307\u5b9a\u3059\u308b\u3068\u30e1\u30c8\u30ea\u30af\u30b9\u304cURL\u3054\u3068\u4fdd\u6301\u3055\u308c\u3001OOME\u306e\u539f\u56e0\u306b\u3082\u306a\u308a\u5f97\u307e\u3059\u3002<\/p>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism undefined-numbers lang-java\" data-lang=\"Java\"><code>webClient.get()\n    .uri(\"\/sample\/{variable}\", \"hoge\")  \/\/ \/sample\/hoge\n    .retrieve()\n    .bodyToMono(String.class);<\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-3\">keepalive\u306e\u7121\u52b9\u5316<\/h2>\n\n\n\n<p>keep-alive\u3092\u7121\u52b9\u5316\u3059\u308b\u306b\u306fHttpClient\u751f\u6210\u6642\u306b<code>keepAlive<\/code>\u306b<code>false<\/code>\u3092\u8a2d\u5b9a\u3057\u307e\u3059\u3002<br>\u203b\u30c7\u30d5\u30a9\u30eb\u30c8\u306f\u6709\u52b9<\/p>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism undefined-numbers lang-java\" data-lang=\"Java\"><code>var httpClient = HttpClient.create(connectionProvider)\n    ...\n    .keepAlive(false)\n    ....<\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-4\">Proxy\u30d8\u30c3\u30c0<\/h2>\n\n\n\n<p>\u4ee5\u4e0b\u3001\u8a8d\u8a3c\u304c\u3042\u308bproxy\u306b\u5bfe\u3057\u3066WebClient\u3092\u4f7f\u3063\u3066\u63a5\u7d9a\u3059\u308b\u3068\u304d\u306e\u5b9f\u88c5\u65b9\u6cd5\u3067\u3059\u3002<\/p>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism undefined-numbers lang-java\" data-lang=\"Java\"><code>    @Bean\n    public WebClient proxyWebClient() {\n        return WebClient.builder()\n                .clientConnector(new ReactorClientHttpConnector(HttpClient.create()\n                        .proxy(typeSpec -&gt; {\n                            typeSpec.type(ProxyProvider.Proxy.HTTP)\n                                    .host(\"localhost\")\n                                    .port(8080)\n                                    \/\/ basic\u8a8d\u8a3c\u306f\u5bfe\u5fdc\u3057\u3066\u3044\u308b\n                                    \/\/.username(\"username\")\n                                    \/\/.password(s -&gt; \"password\")\n                                    .httpHeaders(headers -&gt; {\n                                        \/\/ \u3053\u3053\u3067\u8a8d\u8a3c\u7528\u306e\u30d8\u30c3\u30c0\u3092\u4e57\u305b\u308b\n                                        headers.add(\"uuid\", UUID.randomUUID().toString());\n                                    });\n                        })\n                ))\n                .build();\n    }<\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-5\">\u5358\u4f53\u30c6\u30b9\u30c8<\/h2>\n\n\n\n<p>WebClient\u306e\u5358\u4f53\u30c6\u30b9\u30c8\u306b\u306fOkHttp\u3092\u4f7f\u3046\u3068\u3088\u3044\u3068\u601d\u3044\u307e\u3059\u3002<\/p>\n\n\n\n<p>\u4ee5\u4e0b\u306e\u3088\u3046\u306aWebClient\u306b\u4f9d\u5b58\u3059\u308b\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u3092\u30b5\u30f3\u30d7\u30eb\u306b\u30c6\u30b9\u30c8\u30b3\u30fc\u30c9\u3092\u66f8\u3044\u3066\u307f\u307e\u3059\u3002<\/p>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism undefined-numbers lang-java\" data-lang=\"Java\"><code>@RequiredArgsConstructor\n@Component\npublic class SampleApiClient {\n    private final WebClient webClient;\n\n    public Mono&lt;String&gt; sample() {\n        return webClient.get()\n                .uri(\"\/sample\")\n                .retrieve()\n                .bodyToMono(SampleResponse.class)\n                .map(res -&gt; res.getMessage());\n    }\n\n    @Data\n    public static class SampleResponse {\n        private String message;\n    }\n}<\/code><\/pre><\/div>\n\n\n\n<p>OkHttp\u3092\u4f7f\u7528\u3059\u308b\u305f\u3081\u306b\u3001\u4f9d\u5b58\u3092\u8ffd\u52a0\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism undefined-numbers lang-groovy\" data-file=\"build.gradle\" data-lang=\"Groovy\"><code>dependencies {\n  ...\n  \/\/ \u4f9d\u5b58\u3092\u8ffd\u52a0\n  testImplementation 'com.squareup.okhttp3:okhttp'\n\ttestImplementation 'com.squareup.okhttp3:mockwebserver'\n}<\/code><\/pre><\/div>\n\n\n\n<p>Mock\u7528\u306eHTTP\u30b5\u30fc\u30d0\u3092\u8d77\u52d5\u3057\u3066\u30c6\u30b9\u30c8\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism undefined-numbers lang-java\" data-lang=\"Java\"><code>public class SampleApiClientTest {\n    private static MockWebServer mockServer;\n    private ObjectMapper objectMapper = new ObjectMapper();\n\n    private SampleApiClient sampleApiClient;\n\n    @BeforeEach\n    void beforeEach() {\n        var webClient = WebClient.builder()\n                .baseUrl(\"http:\/\/localhost:\" + mockServer.getPort())\n                .build();\n\n        sampleApiClient = new SampleApiClient(webClient);\n    }\n\n    @BeforeAll\n    static void startMock() throws IOException {\n        mockServer = new MockWebServer();\n        mockServer.start();\n    }\n\n    @AfterAll\n    static void shutdownMock() throws IOException {\n        mockServer.shutdown();\n    }\n\n    @Test\n    @SneakyThrows\n    void test() {\n        \/\/ Mock\u30b5\u30fc\u30d0\u306e\u30ec\u30b9\u30dd\u30f3\u30b9\u3092\u8a2d\u5b9a\u3059\u308b\n        var responseBody = new SampleApiClient.SampleResponse();\n        responseBody.setMessage(\"Hello, world.\");\n        var mockedResponse = new MockResponse()\n                .setBody(objectMapper.writeValueAsString(responseBody))\n                .addHeader(\"Content-Type\", \"application\/json\");\n        mockServer.enqueue(mockedResponse);\n\n        \/\/ \u30ea\u30af\u30a8\u30b9\u30c8\u9001\u4fe1\n        var actual = sampleApiClient.sample();\n\n        StepVerifier.create(actual)\n                .expectNext(\"Hello, world.\")\n                .verifyComplete();\n    }\n}<\/code><\/pre><\/div>\n","protected":false},"excerpt":{"rendered":"<p>WebClient\u3092\u4f7f\u3063\u305f\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u672c\u756a\u904b\u7528\u3059\u308b\u305f\u3081\u306b\u610f\u8b58\u3057\u3066\u304a\u304d\u305f\u3044\u8a2d\u5b9a\u3068\u305d\u306e\u8a2d\u5b9a\u65b9\u6cd5\u3092\u307e\u3068\u3081\u3066\u307f\u307e\u3057\u305f\u3002 \u81ea\u5206\u306e\u73fe\u5834\u3067\u610f\u8b58\u3057\u3066\u3044\u308b\u3053\u3068\u304c\u4e2d\u5fc3\u306b\u306a\u308a\u307e\u3059\u304c\u3001\u30b3\u30d4\u30da\u3067\u305d\u306e\u307e\u307e\u672c\u756a\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306b\u4f7f\u3046\u3088\u3046\u306a\u30b3\u30fc\u30c9 &#8230; <\/p>\n","protected":false},"author":1,"featured_media":215,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[28,13,48],"class_list":{"0":"post-214","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-6","8":"tag-spring-webflux","9":"tag-springboot","10":"tag-webclient"},"jetpack_featured_media_url":"https:\/\/hirabay.net\/wp-content\/uploads\/2023\/01\/SpringBoot_webclient.png","_links":{"self":[{"href":"https:\/\/hirabay.net\/index.php?rest_route=\/wp\/v2\/posts\/214","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hirabay.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hirabay.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hirabay.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/hirabay.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=214"}],"version-history":[{"count":2,"href":"https:\/\/hirabay.net\/index.php?rest_route=\/wp\/v2\/posts\/214\/revisions"}],"predecessor-version":[{"id":307,"href":"https:\/\/hirabay.net\/index.php?rest_route=\/wp\/v2\/posts\/214\/revisions\/307"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/hirabay.net\/index.php?rest_route=\/wp\/v2\/media\/215"}],"wp:attachment":[{"href":"https:\/\/hirabay.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=214"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hirabay.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=214"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hirabay.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=214"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}