【Docker】Dockerネットワークの落とし穴に(勝手に)嵌まった話
最近の活動
スタートアップのプロジェクトのミーティングやら資料やらの準備をしていたらブログを書く時間が...ない!
このブログは更新頻度はぼちぼちでいいから1年間は続けようと考えているので張り切って書いていきますよー!
axiosを使ってAPI通信できない問題
以前の記事で作った環境にて、NginxからLaravelのコンテナにcurlを飛ばすことができました。その際のコマンドは以下のような形、
$ curl http://laravel.test
じゃあaxios
を使ってVueからAPI通信できるな!ヨシッ(某猫並感)
そんなうまい話はありませんでした。
ポート番号を変えてみてもダメ...一体どうして...?となったので調べてみました!
コンテナ同士の見え方
どうやらコンテナ同士の見え方の差が問題だとわかりました!
この場合の見え方の差というのは、Dockerから見たコンテナとブラウザから見たコンテナの見え方の差です。
現在のDockerの構成を図解するとこんな感じ、緑の枠内全体が同じネットワークに設定されています。laravel.test
というコンテナ名でNginxからLaravelにアクセスできたことからも同一ネットワークに配置できていることがわかります。
一方で、ブラウザからDockerのコンテナ名であるlaravel.test
というアドレスはどう解釈されるのでしょうか?
繋がらないんですね。要するにDockerからコンテナ名でアクセスできても、それはDocker内だけの話であってホストのブラウザからは何も見えないわけです。
ここまで来たらaxios
で通信できなかった理由がわかるのではないでしょうか。そう、JavaScriptはブラウザに読み込まれてから実行されます。ブラウザから見れないものがJavaScriptからはアクセスできるはずがないというわけです。
解決法
簡単です。ブラウザから見てアクセスできるアドレスでリクエストを飛ばしてやればいいわけです。今回のLaravelサーバはDockerのlocalhost:80
でリッスンしているポートを3000ポートに転送しています。
つまり、localhost:3000
にリクエストを飛ばせばいいわけですね!とは言ってもポートが違うのでクロスオリジンアクセスを許可しないといけません。まずはその設定から。
プロジェクト名/config/cors.php
'paths' => ['api/*', 'sanctum/csrf-cookie'], 'allowed_methods' => ['*'], 'allowed_origins' => ['*'], 'allowed_origins_patterns' => [], 'allowed_headers' => ['*'], 'exposed_headers' => [], 'max_age' => 0, 'supports_credentials' => true, # 初期false -> trueに
ルートとコントローラの作成
HelloController
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; /** * API用サンプルコントローラ */ class HelloController extends Controller { public function index(){ return response()->json(['message' => 'Hello API!']); } }
/** * APIのサンプルプログラム */ Route::get('/HelloAPI', [HelloController::class, 'index']);
VueのAboutページを編集、Vueのサーバを立ち上げて/aboutにアクセス(※Aboutがない方は vue add router
を実行すると生成されます。)
<template> <div class="about"> <h1 id="message">{{ message }}</h1> </div> </template> <script> import axios from 'axios'; export default { data() { return { message: null } }, // ちゃんとlocalhost:3000にアクセス mounted () { axios .get('http://localhost:3000/api/HelloAPI') .then(response => (this.message = response.data.message)) } } </script>
ふー、これでAPIにアクセスできますね。次はログイン、行ってみますか!