DockerとNuxtのSSRでConnectionRefusedが発生する問題の原因を解説する
Docker上でAPIサーバーとNuxt(SSR)を動かす環境で、connection refusedが発生したりしなかったりする問題に遭遇しました。 今回はその問題の発生原因について書いていきます。
一言で
今回の問題は直アクセス時とnuxt-linkなどでのclientだけで完結する遷移時でasyncDataメソッドの実行場所が違うためです。
どういうこと?
前者のパターン
まずURLをアドレスバーに直打ちしてアクセスします。 この場合、クライアントでは表示すべきHTMLファイルやjsファイルが存在しない状態から処理が始まり、NuxtサーバーではSSRとしてasyncDataメソッドが実行されます。 そのためasyncDataメソッドにAPIアクセス処理があった場合、Dockerとして動くNuxtサーバー上から行われるためコンテナ~コンテナ間通信になります。
後者のパターン
このパターンでは既にクライアントに表示すべきHTMLファイルやjsファイルが存在していてページが表示されている状態とします。
ページが表示された状態からnuxt-link
や$router.push
を使って画面遷移をした場合、NuxtサーバーではなくクライアントでasyncDataメソッドが実行されます。
そのためasyncDataメソッドにAPIアクセス処理があった場合、クライアントからDockerコンテナに対してアクセスされるのでホスト~コンテナ間通信になります。
何が問題?
ホストからDockerコンテナへアクセスする場合localhost:8080
のような形でアクセスできます。
しかしDockerコンテナ間のアクセスではコンテナの名前を元にドメインを解釈するため、api:8080
のようなアドレスが必要になります。
そのためasyncDataメソッドでAPIアクセス処理を書いていると、Nuxtサーバー内で実行される時とクライアントで実行される時の2パターンでは実行結果が変わってしまうといった問題が発生してしまいます。
解決策
サーバー上での実行時と、クライアント上での実行時でURLを変えると解決します! サーバー上ではDockerコンテナ間の通信をする為、コンテナ名依存でURLを設定します。 クライアント上ではDockerコンテナの外からアクセスする為、解釈された後のURLを設定します。
nuxt.config.js
axios: { baseURL: process.env.API_URL, browserBaseURL: process.env.API_URL_BROWSER },
.env
API_URL='http://api:8080/' API_URL_BROWSER='http://localhost:8080'
まとめ
SSRをする場合は常に「APIアクセスがどこから行われるのか?」、「どういう環境で行われるのか?」、「本当にそのアドレスで正しいのか?」を意識するようにしましょう。 理解できればそんなに難しい話ではないということがわかります。