[Golang]ローカルサーバーを立てた～ファイルダウンロード～

初めに
===
Androidアプリからリクエストを投げて、GoでWebServerを立てたローカルサーバー上のファイルをダウンロードする

環境
===
PC Windows10
Android Studio 4.0
Kotlin 1.3.72
Android端末　Emulator(API Level 29)
Go 1.11.1

構成図
===
![go_server.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487320/e8771fc0-f61a-3472-8ab4-5f998bb3e704.png)
Androidアプリからファイル名を指定して、サーバー側にリクエスト、サーバー側に保存されているファイルとステータスコードを返却


実装
===
ローカルサーバー
--

```Server.go
package controllers

import (
    "fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"strings"
)

func apiSampleHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "POST":
		fmt.Println("POST")
	case "GET":                                        // GETのリクエストでファイルDL
		fmt.Println("GET")
		name := fmt.Sprint(r.URL)                      // 「/ファイル名」を取得
		fileName := strings.SplitAfter(name, "/")[1]   // 「ファイル名」を取得
        // ファイルがサーバー側に存在するかのチェック
		if fileinfo, err := os.Stat("./" + fileName); os.IsNotExist(err) || fileinfo.IsDir() {
			fmt.Println("file is not exist")
			w.WriteHeader(http.StatusNotFound)
			return
		}
		buf, err := ioutil.ReadFile("./" + fileName)   // ファイル読み出し 
		if err != nil {
			fmt.Println("file could not be read")
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		w.Write(buf)                                   // レスポンスに書き込む
	}
	w.WriteHeader(http.StatusOK)
}

// main.goから呼び出してサーバーを起動
func StartWebServer() error {
	http.HandleFunc("/", apiSampleHandler)
	return http.ListenAndServe(":8080", nil)
}
```
main.goを実行し、サーバーを起動
http://localhost:8080 にアクセスして、サーバーが起動していることを確認

ファイルを準備
===
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487320/e92eac10-5bb6-a0b8-a3d4-bef5d4388451.png)
ダウンロードする用のファイルをmain.goと同じディレクトリに配置

Android アプリ
--
1．Androidmanifest.xml
-
インターネットにアクセスするためのPermissionを定義

```AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
```

Android 9.0からhttpの通信の設定がOFFになるので```usesCleartextTrafic```をtrueに設定

```AndroidManifest.xml
<application
     省略
    android:usesCleartextTraffic="true">
    <activity android:name=".MainActivity">
        省略
    </activity>
</application>
```

2．サーバーアクセス
-
http通信でサーバーにGETでアクセスする

```Net.kt
   fun requestFileDownload(context: Context, requestUrl: String, fileName: String): Int {
        val url = URL("$requestUrl/$fileName.txt")     // URLオブジェクト生成
        // UrlConnectionオブジェクト生成
        val urlConnection = url.openConnection() as HttpURLConnection 
        var result = ""
        var responseCode = 0
        try {
            urlConnection.requestMethod = "GET"         // POST, GETなど
            urlConnection.doInput = true                // レスポンスボディの受信
            urlConnection.useCaches = false             // キャッシュの利用
            urlConnection.connect()                     // コネクションを確立

            responseCode = urlConnection.responseCode   // レスポンスコードを取得
            when (responseCode) {
                HttpURLConnection.HTTP_OK -> {          // レスポンスコードが200：OKの時だけ処理
                    val path = context.filesDir.toString() + "/" + fileName + FILE_EXPAND
                    // レスポンスの内容を読み出す
                    DataInputStream(urlConnection.inputStream).use { fileInputStream ->
                        // ファイルを作成し書き込む
                        DataOutputStream(BufferedOutputStream(FileOutputStream(path))).use {
                            val buffer = ByteArray(BUFFER_SIZE)
                            var byteRead: Int
                            do {
                                byteRead = fileInputStream.read(buffer)
                                if (byteRead == -1) {
                                    break
                                }
                                it.write(buffer, 0, byteRead)
                            } while (true)
                        }
                    }
                }
            }
        } catch (e: Exception) {
            Log.e("Net", "#startConnection$e")
        } finally {
            urlConnection.disconnect()
        }
        return responseCode
    }
}
```

3．IPアドレスの確認
-
アクセスしたいサーバー（PC）のIPアドレスをcommand promptで以下を実行し確認

```
>ipconfig
```
4．PCとAndroid端末を同一のネットワーク環境に接続
-
5．Androidにて接続
-
Net#requestFileDownloadのrequestUrlにhttp://{確認したIPアドレス}:8080を設定
Net#requestFileDownloadのfileNameにダウンロードするファイル名を設定し実行

ファイルのダウンロードを確認
===
アプリ固有領域（```/data/data/{package_name}/files```配下）にファイルが生成されていることを確認
[Device File Explorer でデバイス上のファイルを表示する](https://developer.android.com/studio/debug/device-file-explorer?hl=ja
)

最後に
===
全体ソースは[こちら](https://github.com/kurramkurram/GoServer)
アクセス先やRequestMethod、ファイル名はアプリで動的に変更できるようにしています。

サーバーへのファイルアップロードは[こちら](https://qiita.com/kurramkurram/items/262cd1d2f01dcb6fa8bd)

参考文献
===
Goサーバー側
-
[Package http](https://golang.org/pkg/net/http/)
[Go言語 (golang) ファイル・ディレクトリの存在チェック](https://www.sukerou.com/2017/08/go-golang.html)
[[Golang] ファイル読み込みサンプル](https://qiita.com/tchnkmr/items/b686adc4a7e144d48755)


Androidアプリ側
-
[Java で HTTP でファイルをダウンロードして保存する方法](https://java.keicode.com/lang/http-download-and-save.php)