参考にさせていただいたページ
fetchの第一引数について
CORSの設定について
- Next.js + Rails プロジェクトのセットアップ手順
- RailsでAPIにCORSを設定する - Qiita
- Next.js + Ruby on Rails(APIモード) on Docker 構築手順
はじめに
今回の私のポイントとしては以下のようなことでした。
- fetchの第一引数にはどういうURL文字列を渡したら良いか
- RailsのCORSの設定をどうやったら良いか
frontend/pages/index.tsxにgetStaticProps()を定義する
frontend/pages/index.tsxに以下の通り、getStaticProps()を定義して、Homeコンポーネントでpropsを受け取るようにしました。
〜略〜 export const getStaticProps = async () => { const response = await fetch('http://nginx:8000/api/tasks'); const json = await response.json(); return { props: json, }; }; const Home: NextPage = (props) => { console.log(props); 〜略〜 } export default Home
fetchの第一引数は "http://[サービス名]:[ポート番号]/api/tasks"
みたいな感じで渡すと大丈夫でした。
RailsのCORSの設定
rails/Gemfileの編集
以下の行を追記しました。
gem 'rack-cors'
bundle install
% docker-compose run --rm app bundle install
build
Gemfileを編集したのでbuildし直します。
% docker-compose build
rails/config/initializers/cors.rbの作成とその記述内容
% vim rails/config/initializers/cors.rb
以下の通り記述しました。
Rails.application.config.middleware.insert_before 0, Rack::Cors do allow do origins "*" resource "*", headers: :any, methods: [:get, :post, :put, :patch, :delete, :options, :head] end end
rails/config/environments/development.rbの編集
rails/config/environments/development.rbのendの内側の一番下にconfig.hosts << "nginx"
と一行追記しました。
以下のようになります。
require "active_support/core_ext/integer/time" Rails.application.configure do 〜略〜 # localhost:ポート番号では通信に失敗します。 # fetchの引数に渡しているサービス名と合わせます。 config.hosts << "nginx" end
docker-compose restartする
railsのconfigを変更したので、設定反映のためにrestartします。
% docker-compose restart
ブラウザで確認してみる
以下の「httpのURL」と「httpsのURL」にブラウザでアクセスして、ブラウザのコンソールでpropsが確認できました。
rails/config/initializers/cors.rbを少し修正する
originsはワイルドカードじゃない方が良いと思うので、以下の通り修正します。
Rails.application.config.middleware.insert_before 0, Rack::Cors do allow do origins '127.0.0.1:3000', 'localhost:3000' resource '*', headers: :any, methods: [:get, :post, :put, :patch, :delete, :options, :head] end end
ブラウザで確認してみる
一度restartします。
% docker-compose restart
以下の「httpのURL」と「httpsのURL」にブラウザでアクセスして、ブラウザのコンソールでpropsが確認できたら完成かなと思います。
railsアプリケーションの「タスクの新規登録」が動かなくなっていたので直す
だいぶ後になってわかったことですが、CORSを設定したことによって動かなくなっていたようです。
大事なのでここに追記しておきます。
「タスクの新規登録」ページからPOSTすると以下のエラーが出るようになりました。
ActionController::InvalidAuthenticityToken (HTTP Origin header (https://web-bonsai.com) didn't match request.base_url (http://web-bonsai.com)):
「【Rails/Nginx/ELB 】ActionController::InvalidAuthenticityToken HTTP Origin header (https://example.com) didn’t match request.base_url (http://example.com)の解決法|Rubinistを目指す新米エンジニアのTECH BLOG」を参考にさせていただいて解決しました。
以下の行を追記します。
proxy_set_header X-Forwarded-SSL on;
おまけ
上手くいかない場合1
Uncaught FetchError: request to http://localhost:8000/api/tasks failed, reason: connect ECONNREFUSED 127.0.0.1:8000
のようなエラーが表示されて上手くいかない場合は、fetchの第一引数が適切でないかもしれません。
上手くいかない場合2
FetchError: invalid json response body at http://nginx:8000/api/tasks reason: Unexpected token < in JSON at position 0
のようなエラーが表示されて上手くいかない場合は、以下のようにgetStaticPropsの中で console.log(response)
して、responseを確認してみると良いと思います。
export const getStaticProps = async () => { const response = await fetch('http://nginx:8000/api/tasks'); console.log('==============================') console.log(response) console.log('==============================') const json = await response.json(); return { props: json, }; };
ターミナルを見ると以下のように403エラーが出力されていると思います。
============================== Response { size: 0, timeout: 0, [Symbol(Body internals)]: { body: PassThrough { _readableState: [ReadableState], _events: [Object: null prototype], _eventsCount: 2, _maxListeners: undefined, _writableState: [WritableState], allowHalfOpen: true, [Symbol(kCapture)]: false, [Symbol(kCallback)]: null }, disturbed: false, error: null }, [Symbol(Response internals)]: { url: 'http://nginx:8000/api/tasks', status: 403, statusText: 'Forbidden', headers: Headers { [Symbol(map)]: [Object: null prototype] }, counter: 0 } } ==============================
そんなときはRailsのCORSの設定が上手くいっていないとか、docker-compose restartを忘れてるのかもしれません。