HTTP接続クライアント。HttpClientまたはOkHttpを選択しますか?

著者:博士甘いことでhttps://www.jianshu.com/p/68c30beca612

前に書く

友達とおしゃべりしてこの記事を書いたのはなぜですか

これは私の知識の盲点に再び触れました。最初に、私はバイドゥに学びました。キーワードhttpclientとokhttpの違いに基づいて直接検索し、パフォーマンスを比較しました。希望する答えが見つかりませんでした。私はこの質問をしました、そしてあなたを失望させません

だから、使用法、パフォーマンス、タイムアウト設定の点で比較してください

使用する

HttpClientとOkHttpは通常、他のサービスを呼び出すために使用されます。一般的なサービスによって公開されるインターフェースはhttpであり、httpの一般的なリクエストタイプはGET、PUT、POST、DELETEです。したがって、これらのリクエストタイプの呼び出しが主に導入されます。

HttpClientの紹介

HttpClientを使用したリクエストの送信は、主に次のステップに分けられます。

  • CloseableHttpClientオブジェクトまたはCloseableHttpAsyncClientオブジェクトを作成します。前者は同期、後者は非同期です

  • Httpリクエストオブジェクトを作成する

  • executeメソッドを呼び出してリクエストを実行します。非同期リクエストの場合は、実行する前にstartメソッドを呼び出す必要があります

接続を作成します。

CloseableHttpClient httpClient = HttpClientBuilder.create().build();  

この接続は同期接続です

GETリクエスト:

@Test  
public void testGet() throws IOException {  
    String api = "/api/files/1";  
    String url = String.format("%s%s", BASE_URL, api);  
    HttpGet httpGet = new HttpGet(url);  
    CloseableHttpResponse response = httpClient.execute(httpGet);  
    System.out.println(EntityUtils.toString(response.getEntity()));  
}  

HttpGetを使用して接続がGETリクエストであることを示し、HttpClientがexecuteメソッドを呼び出してGETリクエストを送信します

PUTリクエスト:

@Test  
public void testPut() throws IOException {  
    String api = "/api/user";  
    String url = String.format("%s%s", BASE_URL, api);  
    HttpPut httpPut = new HttpPut(url);  
    UserVO userVO = UserVO.builder().name("h2t").id(16L).build();  
    httpPut.setHeader("Content-Type", "application/json;charset=utf8");  
    httpPut.setEntity(new StringEntity(JSONObject.toJSONString(userVO), "UTF-8"));  
    CloseableHttpResponse response = httpClient.execute(httpPut);  
    System.out.println(EntityUtils.toString(response.getEntity()));  
}  

POSTリクエスト:

オブジェクトを追加

@Test  
public void testPost() throws IOException {  
    String api = "/api/user";  
    String url = String.format("%s%s", BASE_URL, api);  
    HttpPost httpPost = new HttpPost(url);  
    UserVO userVO = UserVO.builder().name("h2t2").build();  
    httpPost.setHeader("Content-Type", "application/json;charset=utf8");  
    httpPost.setEntity(new StringEntity(JSONObject.toJSONString(userVO), "UTF-8"));  
    CloseableHttpResponse response = httpClient.execute(httpPost);  
    System.out.println(EntityUtils.toString(response.getEntity()));  
}  

リクエストはオブジェクトを作成するリクエストであり、json文字列を渡す必要があります

ファイルをアップロード

@Test  
public void testUpload1() throws IOException {  
    String api = "/api/files/1";  
    String url = String.format("%s%s", BASE_URL, api);  
    HttpPost httpPost = new HttpPost(url);  
    File file = new File("C:/Users/hetiantian/Desktop/学习/docker_practice.pdf");  
    FileBody fileBody = new FileBody(file);  
    MultipartEntityBuilder builder = MultipartEntityBuilder.create();  
    builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);  
    builder.addPart("file", fileBody);  //addPart上传文件  
    HttpEntity entity = builder.build();  
    httpPost.setEntity(entity);  
    CloseableHttpResponse response = httpClient.execute(httpPost);  
    System.out.println(EntityUtils.toString(response.getEntity()));  
}  

addPart経由でファイルをアップロードする

DELETEリクエスト:

@Test  
public void testDelete() throws IOException {  
    String api = "/api/user/12";  
    String url = String.format("%s%s", BASE_URL, api);  
    HttpDelete httpDelete = new HttpDelete(url);  
    CloseableHttpResponse response = httpClient.execute(httpDelete);  
    System.out.println(EntityUtils.toString(response.getEntity()));  
}  

キャンセルをリクエストしました:

@Test  
public void testCancel() throws IOException {  
    String api = "/api/files/1";  
    String url = String.format("%s%s", BASE_URL, api);  
    HttpGet httpGet = new HttpGet(url);  
    httpGet.setConfig(requestConfig);  //设置超时时间  
    //测试连接的取消  

    long begin = System.currentTimeMillis();  
    CloseableHttpResponse response = httpClient.execute(httpGet);  
    while (true) {  
        if (System.currentTimeMillis() - begin > 1000) {  
          httpGet.abort();  
          System.out.println("task canceled");  
          break;  
      }  
    }  

    System.out.println(EntityUtils.toString(response.getEntity()));  
}  

リクエストの実行結果をキャンセルするには、abortメソッドを呼び出します。

task canceled  
cost 8098 msc  
Disconnected from the target VM, address: '127.0.0.1:60549', transport: 'socket'  

java.net.SocketException: socket closed...【省略】  

OkHttpの使用

OkHttpを使用したリクエストの送信は、主に次のステップに分けられます。

  • OkHttpClientオブジェクトを作成する

  • リクエストオブジェクトの作成

  • 要求オブジェクトを呼び出しとしてカプセル化

  • Callを使用して同期または非同期リクエストを実行し、executeメソッドを呼び出して同期的に実行し、enqueueメソッドを呼び出して非同期的に実行します

接続を作成します。

private OkHttpClient client = new OkHttpClient();  

GETリクエスト:

@Test  
public void testGet() throws IOException {  
    String api = "/api/files/1";  
    String url = String.format("%s%s", BASE_URL, api);  
    Request request = new Request.Builder()  
            .url(url)  
            .get()   
            .build();  
    final Call call = client.newCall(request);  
    Response response = call.execute();  
    System.out.println(response.body().string());  
}  

PUTリクエスト:

@Test  
public void testPut() throws IOException {  
    String api = "/api/user";  
    String url = String.format("%s%s", BASE_URL, api);  
    //请求参数  
    UserVO userVO = UserVO.builder().name("h2t").id(11L).build();  
    RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"),  
    JSONObject.toJSONString(userVO));  
    Request request = new Request.Builder()  
            .url(url)  
            .put(requestBody)  
            .build();  
    final Call call = client.newCall(request);  
    Response response = call.execute();  
    System.out.println(response.body().string());  
}  

POSTリクエスト:

オブジェクトを追加

@Test  
public void testPost() throws IOException {  
    String api = "/api/user";  
    String url = String.format("%s%s", BASE_URL, api);  
    //请求参数  
    JSONObject json = new JSONObject();  
    json.put("name", "hetiantian");  
    RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"),     String.valueOf(json));  
    Request request = new Request.Builder()  
            .url(url)  
            .post(requestBody) //post请求  
           .build();  
    final Call call = client.newCall(request);  
    Response response = call.execute();  
    System.out.println(response.body().string());  
}  

ファイルをアップロード

@Test  
public void testUpload() throws IOException {  
    String api = "/api/files/1";  
    String url = String.format("%s%s", BASE_URL, api);  
    RequestBody requestBody = new MultipartBody.Builder()  
            .setType(MultipartBody.FORM)  
            .addFormDataPart("file", "docker_practice.pdf",  
                    RequestBody.create(MediaType.parse("multipart/form-data"),  
                            new File("C:/Users/hetiantian/Desktop/学习/docker_practice.pdf")))  
            .build();  
    Request request = new Request.Builder()  
            .url(url)  
            .post(requestBody)  //默认为GET请求,可以不写  
            .build();  
    final Call call = client.newCall(request);  
    Response response = call.execute();  
    System.out.println(response.body().string());  
}  

addFormDataPartメソッドを使用してフォームアップロードファイルをシミュレートする

DELETEリクエスト:

@Test  
public void testDelete() throws IOException {  
  String url = String.format("%s%s", BASE_URL, api);  
  //请求参数  
  Request request = new Request.Builder()  
          .url(url)  
          .delete()  
          .build();  
  final Call call = client.newCall(request);  
  Response response = call.execute();  
  System.out.println(response.body().string());  
}  

キャンセルをリクエストしました:

@Test  
public void testCancelSysnc() throws IOException {  
    String api = "/api/files/1";  
    String url = String.format("%s%s", BASE_URL, api);  
    Request request = new Request.Builder()  
            .url(url)  
            .get()    
            .build();  
    final Call call = client.newCall(request);  
    Response response = call.execute();  
    long start = System.currentTimeMillis();  
    //测试连接的取消  
    while (true) {  
         //1分钟获取不到结果就取消请求  
        if (System.currentTimeMillis() - start > 1000) {  
            call.cancel();  
            System.out.println("task canceled");  
            break;  
        }  
    }  

    System.out.println(response.body().string());  
}  

cancelメソッドを呼び出して、テスト結果をキャンセルします。

task canceled  
cost 9110 msc  

java.net.SocketException: socket closed...【省略】  

まとめ

OkHttpはビルドモードを使用してオブジェクトをより簡潔に作成し、.post / .delete / .put / .getメソッドを使用してリクエストタイプを示します。HttpClientなどのメソッドでHttpGetやHttpPostなどを作成してリクエストタイプを作成する必要はありません

依存関係パッケージで、HttpClientが非同期要求を送信してファイルのアップロードを実現する必要がある場合、追加の非同期要求依存関係を導入する必要があります

 <!---文件上传-->  
 <dependency>  
     <groupId>org.apache.httpcomponents</groupId>  
     <artifactId>httpmime</artifactId>  
     <version>4.5.3</version>  
 </dependency>  
 <!--异步请求-->  
 <dependency>  
     <groupId>org.apache.httpcomponents</groupId>  
     <artifactId>httpasyncclient</artifactId>  
     <version>4.5.3</version>  
 </dependency>  

リクエストをキャンセルするには、HttpClientがabortメソッドを使用し、OkHttpがcancelメソッドを使用します。これは非常に簡単です。非同期クライアントを使用している場合は、メソッドを呼び出して、例外がスローされたときにリクエストをキャンセルできます。

タイムアウト設定

HttpClientタイムアウト設定:

HttpClient 4.3以降では、タイムアウト設定はRequestConfigで設定されます

private CloseableHttpClient httpClient = HttpClientBuilder.create().build();  
private RequestConfig requestConfig =  RequestConfig.custom()  
        .setSocketTimeout(60 * 1000)  
        .setConnectTimeout(60 * 1000).build();  
String api = "/api/files/1";  
String url = String.format("%s%s", BASE_URL, api);  
HttpGet httpGet = new HttpGet(url);  
httpGet.setConfig(requestConfig);  //设置超时时间  

タイムアウトは、HttpClientではなく、リクエストタイプHttpGetに設定されます。

OkHttpタイムアウト設定:

OkHttpに直接設定

private OkHttpClient client = new OkHttpClient.Builder()  
        .connectTimeout(60, TimeUnit.SECONDS)//设置连接超时时间  
        .readTimeout(60, TimeUnit.SECONDS)//设置读取超时时间  
        .build();  

要約:

クライアントがシングルトンモードの場合、HttpClientはタイムアウトをより柔軟に設定でき、リクエストタイプごとに異なるタイムアウト時間を設定します。OkHttpがタイムアウト時間を設定すると、すべてのリクエストタイプのタイムアウト時間も決定されます

HttpClientとOkHttpのパフォーマンス比較

テスト環境:

  • CPU 6コア

  • メモリ8G

  • ウインドウズ10

各テストケースは、チャンスを除いて5回テストされます

クライアント接続はシングルトンです。

クライアント接続はシングルトンではありません:

シングルトンモードでは、HttpClientの応答速度が速く、単位はミリ秒です。パフォーマンスの違いはそれほど変わりません。

非シングルトンモードでは、OkHttpのパフォーマンスが向上し、HttpClientは接続を作成するのにより多くの時間を要します。これは、ほとんどの場合、これらのリソースはシングルトンモードで書き込まれるため、図1のテスト結果がより価値があるためです。

まとめ

OkHttpとHttpClientは、パフォーマンスと用途が区別されず、実際のビジネスに応じて選択できます。

私はブログを読んで詳細を読むことをお勧めします:

1. Java JVM、コレクション、マルチスレッド、新機能シリーズのチュートリアル

2. Spring MVC、Spring Boot、Spring Cloudシリーズのチュートリアル

3. Maven、Git、Eclipse、Intellij IDEAシリーズのツールチュートリアル

4. Java、バックエンド、アーキテクチャ、Alibabaおよびその他の主要メーカーに対する最新のインタビューの質問

人生は美しいです、また明日ね

オリジナルの記事を474件公開 1030年に賞賛 144万回の閲覧+

おすすめ

転載: blog.csdn.net/youanyyou/article/details/105431797