Nuxt.js の CORS 回避の方法と環境変数の設定方法


Prologue

外部APIを使おうとしたときに、CORSで引っかかってしまいました。良いきっかけと思い、Nuxt.js での回避方法と、その際 Proxy を使ったため、環境変数を使用してURLをDev環境とProd環境で切り替える方法を調べました。

基本はDocument通りになるため、自身で設定する場合には都度公式を確認することをお勧めします。

環境

  • macOS: v10.15.5
  • node.js: v12.18.2
  • terminal: iTerm
  • エディタ: VS Code
  • パッケージマネージャ: yarn

CORS の回避

外部APIを使った際に、以下のようなエラーが出ました。

エラー:

Access to XMLHttpRequest at 'https://zipcloud.ibsnet.co.jp/api/search?zipcode=3110105' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

CORS policy によってブロックされた、という内容です。

CORSに関しては以下の記事がわかりやすかったです。

参考: https://qiita.com/att55/items/2154a8aad8bf1409db2b

APIを使うオリジンから別のオリジン(APIがあるオリジン)へのアクセスが許可されていないのが原因で起こったため、プロキシを利用してこのエラーを回避します。

参考:

@nuxt/proxy のインストールと設定

yarn add @nuxtjs/proxy

nuxt.config.ts に追記

// 略
modules: [
        'nuxt-buefy',
        '@nuxtjs/axios',
        '@nuxtjs/proxy' // add
    ],
    proxy: {
        '/api/': {
            target: 'https://zipcloud.ibsnet.co.jp',
            changeOrigin: true,
            secure: false
        }
    }

あるいは

  proxy: {
      '/api/': {
          target: 'https://zipcloud.ibsnet.co.jp/api',
          pathRewrite: {
              '^/api/': '/'
          }
      }
  }

どちらでも通ることは確認しています。

このAPIを使う箇所は以下のように書き換えています。

  • before
const { data } = await axios.get(
   `https://zipcloud.ibsnet.co.jp/api/search?zipcode=${zipCode}`
);
  • after
const { data } = await axios.get(
   `http://localhost:3000/api/search?zipcode=${zipCode}`
);

envファイルの作成

このままだと、Local環境とProd環境でBASE_URLが変わるため、エラーが発生します。
そのため環境変数を定義し、 build のタイミングでURLを書き換えるように修正します。

参考:

Nuxt.js ではクライアントサイドとバックエンドサイドで共有される環境変数を定義でき、@nuxtjs/dotenv を使用すれば、変数を .env ファイルから contextprocess.env に直接ロードできます。

  1. インストール
yarn add -D @nuxtjs/dotenv

2. nuxt.config.jsbuildModules に追加

buildModules: [
 `@nuxtjs/dotenv`
],

デフォルトではroot下にある .env をロードしますが、options で path を指定できます。

buildModules: [
    ['@nuxtjs/dotenv', {
        path: '/path/to/my/global/env/'
    }]
]

また、異なる環境のために異なる設定ファイルを override できるとのことです。
以下実装に入ります。

実装

.env ファイルに以下を追加

BASE_URL = 'http://localhost:3000'

API の URL を環境変数にセットし、Component 内を置き換えます。

const { data } = await axios.get(
  `${process.env.BASE_URL}/api/search?zipcode=${zipCode}` // After
  // `http://localhost:3000/api/search?zipcode=${zipCode}` // Before
);

ファイル名を .env.development に変更し、 nuxt.config.jsdotenv の options を設定します。

この options ですが buildModules プロパティ内に記載すると ✖ Nuxt Fatal Error TypeError: The 'request' argument must be string. Received type undefined というエラーが出たため、下記の方法で対応しました。

理由はわからないですが、 buildModules@nuxt/typescript-build もあったため、切り分けができなかった可能性?かと推測しました。とりあえず今回はファイルが切り替わることが最終目的のため、ここはスルーします。

 buildModules: [
   '@nuxt/typescript-build',
   `@nuxtjs/dotenv`
 ],
 dotenv: {
   filename: `.env.development`
 },

Dev環境とProd環境で読み込む設定ファイルを切り替える

参考: https://ja.nuxtjs.org/api/configuration-dev/

process.env.NODE_ENVnuxt (yarn dev) コマンド実行の際には development となるようなので、それを利用します。

package.json の script を以下のように変更します。

  "scripts": {
    "dev": "nuxt-ts",
    "build": "NODE_ENV=production  nuxt-ts build",
    "start": "nuxt-ts start",
    "generate": "nuxt-ts generate",
    "lint:js": "eslint --ext .js,.vue --ignore-path .gitignore .",
    "lint": "yarn lint:js",
    "test": "jest"
  },

nuxt.config.js は以下のように書き換えます。

dotenv: {
  filename: `.env.${process.env.NODE_ENV}`
},

あるいは以下のように設定してもOK.

const environment = `.env.${process.env.NODE_ENV}`

export default {
  // 略
  dotenv: {
    filename: environment
  },

yarn build コマンド実行の際に、環境変数 NODE_ENVproduction に設定され、環境変数ファイルの読み込みは .env.production に変更される、という流れになります。

注意点として、process.env は利用可能であっても未定義で、 process.env.*** とすることによって個別にマップされてコンパイル時に変換されます。
そのため、 Debug 等する際には console.log(process.env.***) と取るように気を付けてください。
参考: https://ja.nuxtjs.org/api/configuration-env/#processenv--

Epilogue

公式のドキュメントを追いながら理解を進めることができたので、これまでのなんとなく、を多少解消できたと思います。
ただ、細かい部分や公式で明言されていない部分等は多分こういうことを言っているんだろう...と思って書いた部分もあるため、もし間違いがありましたら教えてください。

機会があればVue.jsでの方法もトライしてみます!