JavaでOkHttpを使ってみる

f:id:ts0818:20210506232436j:plain

光通信(ひかりつうしん)とは伝送媒体に光ファイバーを利用した有線通信を行うことである。

光通信 - Wikipedia

第5世代移動通信システム(だい5せだいいどうつうしんシステム、英語5th Generation Mobile Communication System, 「5G)とは、1G2G3G3.9G4Gに続く国際電気通信連合 (ITU) が定める規定「IMT-2020」を満足する無線通信システムである。一般的に英語の"5th Generation"から、「5G」(ファイブジージー)と略される。

第5世代移動通信システム - Wikipedia

⇧ 「光通信」は「有線通信」で「5G」は「無線通信」なんですね。

宇宙だと、

www.kenkai.jaxa.jp

電波は周波数によりその使い方が定められ、また干渉を避けるため、使用にあたって様々な制約が付きます。
さらに、データ量の増大に対して使用可能な帯域が限られる(20 GHz帯で数GHz)ため、通信速度の高速化が難しくなります。
一方、光は電波と比べて桁違いに広い帯域(波長1.5 μm帯で、5 THz)を有するので、電波より多くの情報を送ることが出来ます。また非常に絞ったビームを使用するため、干渉や傍受の恐れがありません。将来の宇宙での高速大容量通信の実現には、光の活用が不可欠です。

光衛星通信技術の研究|JAXA|研究開発部門

⇧「光通信」に力を入れたい感じなんですね。

そんなこんなで、今回はJavaについてです。

レッツトライ~。

 

OkHttpって?

説明を見る限り、 

square.github.io

HTTP is the way modern applications network. It’s how we exchange data & media. Doing HTTP efficiently makes your stuff load faster and saves bandwidth.

https://square.github.io/okhttp/

OkHttp is an HTTP client that’s efficient by default:

  • HTTP/2 support allows all requests to the same host to share a socket.
  • Connection pooling reduces request latency (if HTTP/2 isn’t available).
  • Transparent GZIP shrinks download sizes.
  • Response caching avoids the network completely for repeat requests.

https://square.github.io/okhttp/

⇧ ってな感じで、「HTTP client」ってことらしい。

By the way、「Jetty」の説明では、

www.eclipse.org

f:id:ts0818:20210430145904p:plain

Jetty’s HttpClient supports the BASIC and DIGEST authentication mechanisms defined by RFC 7235, as well as the SPNEGO authentication mechanism defined in RFC 4559.

https://www.eclipse.org/jetty/documentation/jetty-11/programming_guide.php

⇧ってな感じなんだけど、「Jetty」というのは、

Jetty は、100%Javaで開発されたJava ServletコンテナWebサーバである。WebSocketなどのプロトコルもサポートする。Jetty はオープンソースプロジェクトとして開発され、Apache 2.0 License でリリースされている。JBossApache Geronimoといった他のプロジェクトでも利用されている。

Jetty - Wikipedia

Java製の「Java Servletコンテナ/Webサーバー」ですと。

このあたりが、Javaのややこしいところなんだけど、「OkHttp」のように「HTTP client」のみの機能しかないものがある一方で、「Jetty」のように「HTTP client」「Http Server」の両方の機能を持つものもありますと。

話は元に戻りまして、「OkHttp」を利用するにあたっての要件を見てみると、

github.com

Requirements

OkHttp works on Android 5.0+ (API level 21+) and Java 8+.

OkHttp depends on Okio for high-performance I/O and the Kotlin standard library. Both are small libraries with strong backward-compatibility.

https://github.com/square/okhttp

⇧ なんか、「Android」向けを想定してたのかな? 

アーキテクチャを見た感じでは、 

⇧ なんか、「Servletフィルター」みたいな感じで、「Request」とか「Response」に処理を挟み込むことができるみたいね。

 

JavaのHTTP clientって何があるの?

Javaの入門なんかだと、「Servlet」でHTTP通信できちゃうから、「HTTP client」って特に意識しないこと、あるあるだと思うんだけれど、Javaの「HTTP client」ってどんなものがあるのか?

qiita.com

news.mynavi.jp

⇧ 上記サイト様が詳しいです。

 

Servletとの違いは?

Servletはレスポンスを返すだけの存在って感じですかね。 

beginnersbook.com

⇧ なので、上図で言うところの「Cient」にあたる部分に「HTTP client」が当てはまる感じですかね。

なので、「HTTP client」については、対外システムに対してなんかの通信で利用されるようなイメージですかね。

イメージ的には、以下のような感じで、

f:id:ts0818:20210430162956p:plain

⇧ 開発しているプロジェクトの外部のシステムに対してアクセスする場合に利用できるライブラリって感じですかね。なので、「Server」側で「HTTP client」が使われることもあるってことですかね。

対外システムが連携されてる例としては、

www.itmedia.co.jp

⇧ クレジット決済システムなんかが、もってこいと言った感じでしょうか。

通信先の対外システムが、Javaではないプログラミング言語で構築されていた場合でも、「HTTP client」は「HTTPプロトコル」に準拠した「request」「response」を処理するだけなので、とにかく「HTTP通信」だけ意識すれば良いということですかね。

ただ、Javaの場合、対外システムと通信するのであれば「HTTP client」の代わりに「JMS(Java Message Service)」とかの選択肢もありますかね。

話を「HTTP client」に戻すと、「HTTP client」の通信先として、何らかの「サーバー」が稼働している必要はありますと。

 

というわけで、実際に使ってみる

実際に使ってみますか。

pppurple.hatenablog.com

qiita.com

⇧ 上記サイト様を参考にさせていただきました。

ちなみに、

www.docker.com

⇧「Windows 10 Home」の場合の「WSL 2(Windows Subsystem for Linux 2)」における「Docker Desktop」は上図のような関係になるらしいです。

いまいち、「Dockerコンテナ」がどこに作られるのかが謎なんですが、少なくとも「Docker」は「Linux」環境でしか動かないはずということと、「Virtual Box」や「VMware」などを使ったりしていないということと、

ascii.jp

japan.zdnet.com

⇧「WSL 2(Windows Subsystem for Linux 2)」のGUIの仕組みを見た感じから推測するに、「WSL 2 Linux Kernel」が作り出した空間が「Linux」環境になっていて「Docker deamon」や「Dockerコンテナ」が存在しているんじゃなかろうかと。

とりあえず、今回試す環境は、「WSL 2(Windows Subsystem for Linux 2)」と「Docker Desktop」の関係が分からないので、推測でしかないですが、以下のようなイメージになる感じですかね。 (自分の環境では「CentOS」の仮想マシンは作ってないので、あくまで「WSL 2(Windows Subsystem for Linux 2)」と「Docker Desktop」の関係ってこんな感じなのかな~、っていうイメージです)

f:id:ts0818:20210506175017p:plain
⇧「Nginx」を含んだ「Dockerコンテナ」を「Webサーバー」として、Eclipseで「Gradleプロジェクト」を作成して、Javaの「OkHttp」ライブラリでHTTP通信する感じですかね。

それでは、まずは、「Webサーバー」用として、「Docker Desktop」で「Nginx」の「Dockerイメージ」を「Docker Hub」から取得します。

f:id:ts0818:20210506134040p:plain

そしたら、取得した「Dockerイメージ」から「Dockerコンテナ」を作成・起動で。ポートは「8080番」を開放で。

f:id:ts0818:20210506134454p:plain

f:id:ts0818:20210506134431p:plain

「Dockerコンテナ」が起動されました。「Dockerコンテナ」については「Docker Desktop」で管理されてる感じなんですかね?

「WSL 2(Windows Subsystem for Linux 2)」では「ubuntu」とかの「仮想マシン」は認識されてるみたいなんですが、「Dockerコンテナ」についてはノータッチみたいな感じっぽいのよね。

f:id:ts0818:20210506134849p:plain

とりあえず、ブラウザで「http://localhost:8080」にアクセスすると、「Nginx」に接続できたので、「Webサーバー」の準備はOKですと。

f:id:ts0818:20210506134728p:plain

それでは、Eclipseを起動して、「OkHttp」を利用して「Webサーバー」にアクセスするためのコーディングをしていきます。

Eclipseで「Gradleプロジェクト」を作成して、編集または作成するファイルは以下の水色になってる5つのファイルで。

f:id:ts0818:20210506144131p:plain

「Webサーバー」からのレスポンスの内容を記載する用のファイルとして、「src/main/resources」直下に「header.txt」「body.txt」を作成しておきます。

■/Java_one_hundred_knock_http/build.gradle

/*
 * This file was generated by the Gradle 'init' task.
 *
 * This generated file contains a sample Java Library project to get you started.
 * For more details take a look at the Java Libraries chapter in the Gradle
 * User Manual available at https://docs.gradle.org/6.3/userguide/java_library_plugin.html
 */

plugins {
    // Apply the java-library plugin to add support for Java Library
    id 'java-library'
}

repositories {
    // Use jcenter for resolving dependencies.
    // You can declare any Maven/Ivy/file repository here.
    jcenter()
}

dependencies {
    // This dependency is exported to consumers, that is to say found on their compile classpath.
    api 'org.apache.commons:commons-math3:3.6.1'

    // This dependency is used internally, and not exposed to consumers on their own compile classpath.
    implementation 'com.google.guava:guava:28.2-jre'
	
	// https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp
	implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: '5.0.0-alpha.2'

    // Use JUnit test framework
    testImplementation 'junit:junit:4.12'
}

⇧ 今回は、「JUnit」を使って、HTTP通信できたか確認していくので、「JUnit」も依存関係に追加で。(最近のEclipseであれば、「Gradleプロジェクト」のデフォルトで「JUnit」は依存関係に追加されてるはずだけども)

■/Java_one_hundred_knock_http/src/main/java/Java_one_hundred_knock_http/Library.java

/*
 * This Java source file was generated by the Gradle 'init' task.
 */
package Java_one_hundred_knock_http;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class Library {

	private static final String FILE_DEIRECTORY = "src/main/resources";
	private static final String HEADER_TEXT = "/header.txt";
	private static final String BODY_TEXT = "/body.txt";

    public boolean someLibraryMethod() {
    	try {
			getByOkHttp();
		} catch (IOException e) {
			// TODO 自動生成された catch ブロック
			e.printStackTrace();
		}
        return true;
    }

    private static void getByOkHttp() throws IOException {
    	Request request = new Request.Builder()
    			.url("http://localhost:8080")
    			.get()
    			.build();
    	OkHttpClient client = new OkHttpClient();

    	Response response = client.newCall(request).execute();
    	System.out.println(response.code());
    	writeText(FILE_DEIRECTORY + HEADER_TEXT, response.headers().toString());
    	writeText(FILE_DEIRECTORY + BODY_TEXT, response.body().string());

    }

    private static void writeText(String filePath, String content) {
    	Path path = Path.of(filePath);

    	try {
			Files.writeString(path, content, StandardCharsets.UTF_8);
		} catch (IOException e) {
			// TODO 自動生成された catch ブロック
			e.printStackTrace();
		}
    }
}

■/Java_one_hundred_knock_http/src/test/java/Java_one_hundred_knock_http/LibraryTest.java

/*
 * This Java source file was generated by the Gradle 'init' task.
 */
package Java_one_hundred_knock_http;

import static org.junit.Assert.*;

import org.junit.Test;

public class LibraryTest {
    @Test public void testSomeLibraryMethod() {
        Library classUnderTest = new Library();
        assertTrue("someLibraryMethod should return 'true'", classUnderTest.someLibraryMethod());
    }
}

⇧ で保存したらば、「/src/test/java/Java_one_hundred_knock_http/LibraryTest.java」を選択した状態で右クリックし、「カバレッジ(v)」>「JUnitテスト」を選択。

f:id:ts0818:20210506144856p:plain

テストが成功すると、

f:id:ts0818:20210506145106p:plain

「コンソール」に「レスポンスコード」が表示され、

f:id:ts0818:20210506145145p:plain

「header.txt」と「body.txt」にレスポンスの結果が書き込まれています。

f:id:ts0818:20210506145303p:plain

f:id:ts0818:20210506145323p:plain

⇧「Webサーバー」と通信できたようです。

「Webサーバー」の「Dockerコンテナ」を停止して、削除しておきます。

f:id:ts0818:20210506145829p:plain

f:id:ts0818:20210506145936p:plain

f:id:ts0818:20210506150011p:plain

⇧「Webサーバー」が削除されました。

というわけで、HTTP通信の確認ができましたが、「http://localhost:8080」以外のURLにアクセスするには、「Webサーバー」側でURLに対する処理を用意する必要がありますかね。

今回はこのへんで。