Docker上のReactとRails APIでFetchをする

Docker上にReactとRails API modeを立ち上げていて、React側からRailsへFetchを飛ばしたかったのですが、ハマってしまっていたのでメモ

ReactとRailsは別コンテナで立ち上げており、docker-compose.ymlは次のような構成です。

version: '3'

volumes:
  store:
    driver: local
  bundle:
    driver: local

services:
  nginx:
    build: ./nginx
    ports:
      - 8080:8080
    expose:
      - "8080"
    volumes:
      - ./frontend/dist:/wwwroot:ro
    links:
      - web
  frontend:
    build: ./frontend
    volumes:
      - ./frontend/src:/app/src
      - ./frontend/dist:/app/dist
    links:
      - web
  web:
    build: .
    ports:
      - 3001:3001
    expose:
      - "3001"
    volumes:
      - .:/app
      - bundle:/usr/local/bundle
    links:
      - db
    stdin_open: true
    tty: true
    command: ./scripts/backend.sh
    environment: &app_env
      PORT: 3001
      DB_HOST: db
      DB_PORT: 5432
      DB_NAME: rails_docker_database
      DB_USER: postgres
      DB_PSWD: postgres
  db:
    image: postgres:latest
    ports:
      - 5432:5432
    volumes:
      - store:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: rails_docker_database

これのfrontend(nginx上)とwebをつなげたかったわけで、Reactのコードで次のようにしてFetch(GET)をしようとしていました。

 fetch('http://localhost:3001/users', {
      mode: 'cors',
    })
      .then(response => {
        return response.json();
      })
      .then(json => {
        console.log(json);
      }).catch((err) => {
        console.error(err);
      });

ここでヘッダーを色々変更したり、ホスト名をdocker inspectで調べたコンテナのIPアドレスに変更してみたりしましたが、どれもタイムアウトになったり、corsができないよと怒られていました。

corsの許可はRails側のconfig/application.rbで設定はしていたのですが、結局はこの設定方法がダメだったみたいで、こちらの記事を参考にrack-corsを導入しcors関連を設定し直したところ無事コンテナ間でも通信することができました。

この記事中のconfig/application.rbにおけるENV.fetchのフォールバックをlocalhost:8080(nginxのポート)に設定しFetch API側もlocalhost:3001を指定したところ問題なく通信できていました。

Dockerに載せていない環境であればもっと様々な方法があるかと思いますが、Docker上での構築だとまだバージョンやライブラリによっては不具合も多いらしく、今まで問題なく動作していた方法が通用しない場合もあります。

Dockerにこだわりがないのであれば、構成方法を見直して素直にクラウドサービス等のAPIを利用するかDockerに載せずに外部サーバーに載せてアクセスした方が制約は少ないと思われます。

 

余談ですが、Fetch APIのmodeにno-corsを指定した時は、クロスオリジン通信ができない場合にもエラーは出さずに空のレスポンスが返されるだけなので、エラーが出てないから大丈夫だと思ってはいけないようです。自分はここでno-corsでも通信できる!とハマっていました…