Unity (HoloLens) で通信するために使用できる Httpクライアントのサンプルコード集です。
GETとPOSTそれぞれで、コルーチン、UniRx、async/await(TaskとUniTask)などを織り交ぜながら例を書いています。
目次
TL;DR
- 最新の環境でアセットも自由に使えるのであれば、UnityWebRequest + UniTask を使うのが良いです
- 環境の制約などある場合はそれぞれの実装例を参考にしてください
概要
対象クラス
対象とするクラスは次の通りです。
クラス | 提供元 | 名前空間 | 環境 |
---|---|---|---|
WWW | Unity | UnityEngine | Unity 5.4 より前から |
UnityWebRequest | Unity | UnityEngine.Networking | Unity 5.4 以降 |
HttpWebRequest | .NET | System.Net | .NET Framwork 初期から |
HttpClient | .NET | System.Net.Http | .NET Framework 4.5 以降 |
HttpClient | .NET | Windows.Web.Http | UWP Windows 10.0.10240.0 以降 |
開発環境
- Unity : 2019.3.15f.1
- UniRx : 6.2.2
- UniTask : 2.0.19
- MRTK : 2.4.0
- Visual Studio : 2019
コード全体のプロジェクトはこちらのリポジトリにあります。
サンプル
WWW
GET
コルーチン
コルーチンを使った実装例です。
void Start() { StartCoroutine("GetRequestCoroutine"); } private IEnumerator GetRequestCoroutine() { var www = new WWW(url); yield return www; if (www.error != null) { Debug.Log("failure."); Debug.Log(www.error); } else { Debug.Log(www.text); } }
ヘッダをつけたい場合は次のようにします。
var header = new Dictionary<string, string>() { { "foo", "hoge" } }; var www = new WWW(url, null, header);
Observable from コルーチン
UniRx を使ってコルーチンを Observable に変換する実装例です。
void Start() { Observable.FromCoroutine<string>(observer => GetRequestCoroutine(observer)) .Subscribe(x => Debug.Log(x)) .AddTo(this); } private IEnumerator GetRequestCoroutine(IObserver<string> observer) { var www = new WWW(url); yield return www; if (www.error != null) { Debug.Log("failure."); } else { observer.OnNext(www.text); observer.OnCompleted(); } }
ObservableWWW
UniRx の ObservableWWW を使った実装例です。
ObservableWWW.Get(url) .Subscribe( x => Debug.Log(x), ex => Debug.Log(ex.Message), () => Debug.Log("completed.")) .AddTo(this);
進捗を通知したい場合は、 ScheduledNotifier を作って、Get の引数 progress に渡します。
var progress = new ScheduledNotifier<float>(); progress.Subscribe(prog => Debug.Log(prog)) .AddTo(this); ObservableWWW.Get(url, progress: progress) ...
UniTask
UniTask を使った実装例です。UniTask を使うと、yield return
を await
に置き換える(await する)ことができます。
void Start()
{
await GetRequestAsync();
}
private async UniTask GetRequestAsync() { var www = new WWW(url); await www; if (www.error != null) { Debug.Log("failure."); } else { Debug.Log(www.text); } }
POST
WWW
POST する場合の実装例です。 WWWForm を使います。それ以外の処理の流れは GET と同じになります。
var form = new WWWForm(); form.AddField(key, zipcode); var www = new WWW(url, form);
Formのデータと画像(バイナリ)を送信する場合は、WWWForm
に追加します。
var postData = new byte[] { 1, 2 }; form.AddBinaryData("image", postData, "sample.png", "image/png");
ヘッダをつけて、画像(バイナリ)だけを送信する場合、WWW のコンストラクタに渡します。
var header = new Dictionary<string, string>() { { "foo", "hoge" }, { "Content-Type", "application/octet-stream" }, }; var postData = new byte[] { 1, 2 }; var www = new WWW(url, postData, header);
ObservableWWW
UniRX の ObservableWWW の実装例です。
var form = new WWWForm(); form.AddField(key, zipcode); ObservableWWW.Post(url, form) .Subscribe(x => Debug.Log(x)) .AddTo(this);
UnityWebRequest
GET
コルーチン
コルーチンを使った実装例です。
void Start() { StartCoroutine("GetRequestCoroutine"); } private IEnumerator GetRequestCoroutine() { var request = UnityWebRequest.Get(url); yield return request.SendWebRequest(); if (request.isHttpError || request.isNetworkError) { Debug.Log("failure."); Debug.Log(request.error); } else { Debug.Log(request.downloadHandler.text); } }
ヘッダを付ける場合は、次のようになります。
var request = UnityWebRequest.Get(url); request.SetRequestHeader("foo", "hoge"); request.SetRequestHeader("bar", "fuga");
Observable from コルーチン
UniRx を使ってコルーチンを Observable に変換する実装例です。
void Start() { Observable.FromCoroutine<string>(observer => GetRequestCoroutine(observer)) .Subscribe(x => Debug.Log(x)) .AddTo(this); } private IEnumerator GetRequestCoroutine(IObserver<string> observer) { var request = UnityWebRequest.Get(url); yield return request.SendWebRequest(); if (request.isHttpError || request.isNetworkError) { Debug.Log("failure."); } else { observer.OnNext(request.downloadHandler.text); observer.OnCompleted(); } }
UniTask
UniTask を使った実装例です。UniTask を導入することで await
できるようになります。
void Start() { await GetRequestAsync(); } private async UniTask GetRequestAsync() { var request = UnityWebRequest.Get(url); await request.SendWebRequest(); if (request.isHttpError || request.isNetworkError) { Debug.Log("failure."); } else { Debug.Log(request.downloadHandler.text); } }
UniTask を Observable に変換したい場合は、Hot/Coldの注意が必要です。
// 呼び出しと同時に実行される(Hot) GetRequestAsync().ToObservable(); // Subscribeするまで実行されない(Cold) Observable.Defer(() => GetRequestAsync().ToObservable());
POST
POST する場合の実装例です。 WWWForm を使います。
var form = new WWWForm();
form.AddField(key, zipcode);
var request = UnityWebRequest.Post(url, form);
Form のデータと画像(バイナリ)を送信する場合は、WWWForm に追加します。
var postData = new byte[] { 1, 2 }; form.AddBinaryData("image", postData, "sample.png", "image/png");
ヘッダをつけて、画像(バイナリ)だけを送信する場合、UnityWebRequest
のヘッダとUploadHandlerを設定します。
var request = UnityWebRequest.Post(url, form); request.SetRequestHeader("foo", "hoge"); request.SetRequestHeader("Content-Type", "application/octet-stream"); var postData = new byte[] { 1, 2 }; request.uploadHandler = new UploadHandlerRaw(postData); request.uploadHandler.contentType = "application/octet-stream"; request.downloadHandler = new DownloadHandlerBuffer();
HttpWebRequest
[Api Compability Level] が [.NET 4.x] であれば直接使えます。
GET
Callbak
コールバックを使った非同期の実装例です。
try { var request = WebRequest.Create(url); request.BeginGetResponse(x => { var response = (HttpWebResponse)request.EndGetResponse(x); if (response.StatusCode != HttpStatusCode.OK) { Debug.Log("failure."); } else { using (var reader = new StreamReader(response.GetResponseStream())) { var text = reader.ReadToEnd(); Debug.Log(text); } } }, null); } catch (WebException e) { Debug.Log(e.Message); } catch (Exception e) { Debug.Log(e.Message); }
ヘッダをつけたい場合は次のようにします。
request.Headers.Add("foo", "hoge");
Observable
UniRx で Observable に実装する例です。
Observable.Start(() => { var request = WebRequest.Create(url); var response = request.GetResponse(); using (var reader = new StreamReader(response.GetResponseStream())) { return reader.ReadToEnd(); } }) .Subscribe(x => Debug.Log(x)) .AddTo(this);
GetResponse
には代替となる拡張メソッドが用意されてたりもします。
WebRequest.Create(url) .GetResponseAsObservable() .Select(res => { using (var reader = new StreamReader(res.GetResponseStream())) { return reader.ReadToEnd(); } }) .Subscribe( x => Debug.Log(x), error => Debug.Log(error.Message), () => Debug.Log("completed.")) .AddTo(this); }
UniTask (Task)
async/await を使った実装例です。UniTask は Task に書き換えても動きます。
void Start() { await GetRequestAsync(); } private async UniTask GetRequestAsync() { var request = WebRequest.Create(url); var response = await request.GetResponseAsync(); using (var reader = new StreamReader(response.GetResponseStream())) { var text = reader.ReadToEnd(); Debug.Log(text); } }
POST
POST する場合の実装例です。
var request = WebRequest.Create(url); request.Method = "POST"; var param = $"{key}={zipcode}"; var data = Encoding.ASCII.GetBytes(param); request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = data.Length; using (var stream = request.GetRequestStream()) { stream.Write(data, 0, data.Length); }
画像(バイナリ)を送信する場合の実装例です。
var postData = new byte[] { 1, 2 }; request.ContentType = "image/png"; request.ContentLength = postData.Length; using(var stream = request.GetRequestStream()) { stream.Write(postData, 0, postData.Length); }
ヘッダを付けて、画像(バイナリ)を送信する場合の実装例です。
request.Headers.Add("foo", "hoge"); request.Headers.Add("Content-Type", "application/octet-stream"); var postData = new byte[] { 1, 2 }; request.ContentType = "image/png"; request.ContentLength = postData.Length; using (var stream = request.GetRequestStream()) { stream.Write(postData, 0, postData.Length); }
HttpClient (System.Net.Http)
GET
Task を使った実装例です。 UniTask に書き換えても動きます。
private async Task GetRequestAsync() { var content = new FormUrlEncodedContent(new Dictionary<string, string> { { key, zipcode }, }); var encodedQuery = await content.ReadAsStringAsync(); var response = await httpClient.GetAsync($"{url}?{encodedQuery}"); if (!response.IsSuccessStatusCode) { Debug.Log("failure."); Debug.Log(response.ReasonPhrase); } else { var text = await response.Content.ReadAsStringAsync(); Debug.Log(text); } }
ヘッダを付ける場合の実装例です。
var request = new HttpRequestMessage(HttpMethod.Get, url); request.Headers.Add("foo", "hoge"); var response = await httpClient.SendAsync(request);
次のようにもできますが、HttpClient のデフォルトとなっているので注意が必要です。
httpClient.DefaultRequestHeaders.Add("foo", "hoge");
async/await が使えない場合には、Task.Run
が使えます。
Task.Run(async () =>
{
await Task.Delay(3000);
});
POST
POST する場合の実装例です。 GetAsync
の代わりに PostAsync
を使います。
var content = new FormUrlEncodedContent(new Dictionary<string, string> { { key, zipcode.ToString() }, }); var response = await httpClient.PostAsync(url, content);
画像(バイナリ)を送信する場合の実装例です。
var postData = new byte[] { 1, 2 }; var byteContent = new ByteArrayContent(postData); byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded"); var res = await httpClient.PostAsync(url, byteContent);
こちらは HttpRequestMessage を使った例です。呼び出す時は SendAsync
に代わります。
var request = new HttpRequestMessage(HttpMethod.Post, url); var postData = new byte[] { 1, 2 }; var byteContent = new ByteArrayContent(postData); request.Content = byteContent; request.Content.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); var res = await httpClient.SendAsync(request);
MultipartFormDataContent を使った実装例です。
var request = new HttpRequestMessage(HttpMethod.Post, url); request.Headers.Add("foo", "hoge"); var postData = new byte[] { 1, 2 }; var byteContent = new ByteArrayContent(postData); byteContent.Headers.Add("Content-Type", "image/jpeg"); var data = new MultipartFormDataContent(); data.Add(new StringContent(zipcode.ToString()), key); data.Add(byteContent, "file", "test.jpg"); request.Content = data; var res = await httpClient.SendAsync(request);
サーバーサイドでバイナリを取り出す時には方法が異なるので注意が必要です。
以下は Azure Functions での例です。
ByteArrayContent を直接使った場合は、Body から取り出します。
using(var ms = new MemoryStream()) { req.Body.CopyTo(ms); ms.Position = 0; }
MultipartFormDataContent を使った場合は、File から取り出します。
using(var ms = new MemoryStream()) { req.Form.Files[0].CopyTo(ms); ms.Position = 0; }
HttpClient (Windows.Web.Http)
UWP の WinRT API なので、すべてのコードは #if WINDOWS_UWP
で囲む必要があります。
GET
Task を使った実装例です。 UniTask に書き換えても動きます。
using Windows.Web.Http;
private static readonly HttpClient httpClient = new HttpClient(); public async UniTask GetRequestAsync() { var builder = new UriBuilder(url); builder.Query = query; var response = await httpClient.GetAsync(builder.Uri); if (!response.IsSuccessStatusCode) { Debug.Log("failure."); Debug.Log(response.ReasonPhrase); } else { var text = await response.Content.ReadAsStringAsync(); Debug.Log(text); } }
ヘッダを付ける場合の実装例です。HttpRequestMessage を使って設定します。
var request = new HttpRequestMessage(HttpMethod.Get, builder.Uri); request.Headers.Add("foo", "hoge"); var response = await httpClient.SendRequestAsync(request);
次のようにもできますが、HttpClient のデフォルトとなっているので注意が必要です。
httpClient.DefaultRequestHeaders.Add("foo", "hoge");
POST
POST する場合の実装例です。 GetAsync
の代わりに PostAsync
を使います。
var content = new HttpFormUrlEncodedContent(new Dictionary<string, string> { { key, zipcode.ToString() }, }); var uri = new Uri(url); var response = await httpClient.PostAsync(uri, content); var text = await response.Content.ReadAsStringAsync(); Debug.Log(text);
ヘッダを付けて画像(バイナリ)を送信する場合の実装例です。MultipartFormDataContent を使っています。
var request = new HttpRequestMessage(HttpMethod.Post, uri); request.Headers.Add("foo", "hoge"); var file = await KnownFolders.CameraRoll.GetFileAsync("test.jpg"); var buffer = await FileIO.ReadBufferAsync(file); var byteContent = new HttpBufferContent(buffer); byteContent.Headers.Add("Content-Type", "image/jpeg"); var data = new HttpMultipartFormDataContent(); data.Add(new HttpStringContent(zipcode.ToString()), key); data.Add(byteContent, "file", "test.jpg"); request.Content = data; var res = await httpClient.SendRequestAsync(request);
参考
後から見直したくなりそうなものや、一度目を通しておいたほうが良さそうなものなどを残しておきます。
Unity
- Unityにおける通信APIを色々試して罠を踏んだ話 | CyberAgent Developers Blog
- UnityWebRequestの使い方【Unity】 - (:3[kanのメモ帳]
- Unity2018.3以降でObservableWWWの代替手段 - Qiita
- [Unity/C#]WWW/HttpWebRequestにおける中間者攻撃の危険性を考慮した通信プログラムまとめ - Qiita
- UniRx入門 その3 -ストリームソースの作り方 - Qiita
.NET 一般
- C# HTTPクライアントまとめ - Qiita
- HttpClient詳解、或いは非同期の落とし穴について
- HttpClientをusingで囲わないでください - Qiita
- C# 今更ですが、HttpClientを使う - Qiita
- C# HttpClientでContent-Typeを指定する方法 - 備忘録
- System.Net.Http.HttpClient から Windows.Web.Http.HttpClient への切り替えのメモ - kazuakix の日記