NuxtからLaravelへaxiosで通信してみる(1)

0
142

私はバックエンドのエンジニアですが、昨今故あってNuxtなども触っています。
※本来であればNuxt.js、Vue.jsのように表記することが正しいかと思いますが、面倒なのでここではNuxt、Vueと表示します。
バックエンドの人間がフロントエンド側に関与している以上、最終的にはフロントエンド側からバックエンド側への通信を考えたくなる訳ですが、今回はそのようなお話です。
なお、「Nuxtとは」「Laravelとは」と細かく触れていると話が冗長になるので、その辺の知識はある程度あるものとして、ここでは目的の通信を成立させるための環境構築に特化して話を進めたいと思います。

なお、物理的動作環境はMac、バックエンド側はMac上に仮想サーバをVirtualbox/vagrantで構築、OSはCentOS、システム開発はLaravel(PHP)で行っています。NuxtはMac上に直接環境構築します。
使用している物理的な機械はMac1台ですが、Laravel環境が仮想サーバ上に構築されていることからNuxtとLaravelは論理的には別のマシン上に存在することになります。
また、Nuxtに関してはSSR(Server Side Rendering)機能を利用しますが、これは文字通り「サーバ側で描画する」形態であり、ここでもサーバが出てきます。Nuxt環境を構築し、実際に動かしてみたいとなった時に「npm run dev」または「yarn dev」のようにコマンドを叩くことになるのですが、その状態で同マシン上のブラウザから「http://localhost:3000」なるURLを指定することでNuxt環境にアクセスすることになります。これはNuxt環境としてlocalhostサーバ上のポート3000でアクセス待ちをしているWebサーバアプリが動作していることを意味する訳で、先のコマンドはこのWebサーバアプリを起動するものと考えて良いかと思います。つまりNuxt単体を使用する状態においてもMacはクライアント(ブラウザ動作環境)とサーバ(Webサーバアプリ動作環境)の2役をこなしている訳です。蛇足ながら、設定次第ではNuxtサーバに別マシン(物理的に別でも可)のブラウザからアクセスできるようにすることも可能です。
まとめると、Mac上にはクライアント(ブラウザ動作環境)、Nuxtサーバ、Laravelサーバの3環境が仮想的に存在することになります。
この辺ややこしいですが、後々重要になってきますのでしっかり押さえておきたいところです。

Nuxt環境構築

Nuxt環境を構築するためにはNode.jsをインストールしておく必要がありますが、そちらについてはGoogle先生に聞いていただくと言うことで、ここではいきなりNuxt環境構築から入ります。
Macのターミナル画面を開き、Nuxt環境を構築したいフォルダに移動します。Documents配下に適当なフォルダ(例えばnuxt)を作成し、その配下に環境を構築していくのが良いかと思います。
そこで以下のコマンドを実行します。<プロジェクト名>に指定した名称でフォルダが作成され、その配下にNuxt環境が構築されるので、適した名称を付けると良いです。

npx create-nuxt-app <プロジェクト名>

途中色々と設定内容を聞かれますが、今回指定すべきは以下のみ。それ以外は任意で(単にEnterでもOK)。

? Nuxt.js modules: (Press <space> to select, <a> to toggle all, <i> to invert selection)
❯◯ Axios
 ◯ Progressive Web App (PWA)
 ◯ Content

上記状態でスペースを押すと「Axios」が選択された状態になります。その状態でEnter。

実行完了時にプロジェクトフォルダに移動して「yarn dev」と実行すれば良い旨の表示があると思いますので、それに従います。
そうすると「http://localhost:3000/」と言うアクセスを待ってるっぽいメッセージが表示されますので、ブラウザから同URLにアクセスします。
Nuxt環境構築に問題がなければデフォルトで用意されたNuxtの画面が表示されるかと思います。

Laravel側の実装

Laravel側の環境構築に関しては別記事「Laravel環境構築」に書きましたのでそちらを参照してください。
今回の目的はNuxt側の処理からLaravel側の処理を呼び出し応答を受けることなので、Laravel側としてブラウザ画面に表示するページ(MVCのView部分)を用意する必要はありません。まずは、最もシンプルにGETで呼び出されて固定文字列を返すアクションを作成したいと思います。
まずはコントローラ「app/Http/Controllers/TestController.php」を生成します。

php artisan make:controller TestController

アクションとして次のようなものを用意してみます。

public function test1()
{   
    return response()->json([
        'result' => 'Response from Laravel',
    ]); 
}

上記にGETでアクセスできるようルートの設定を行います。
「routes/web.php」に以下のような記述を追加します。

Route::get('test1', 'TestController@test1');

これだけでOK。
ブラウザから「http://<LaravelサーバのIP>/test1」にアクセスすると、以下のように表示されるはずです。

{"result":"Response from Laravel"}

簡単ですね。

Nuxt(Vue)側のaxios関連処理実装

Nuxt側の処理は「pages/index.vue」およびそこから呼び出されるVueコンポーネントとして実装します。
今回はあくまで動作実験ができれば良いので「pages/index.vue」に直接処理を書いてしまいます。なお、同ファイル内にはデフォルトとしてサンプル的な内容が書かれていますので、バッサリ捨てて以下のように書き直します。

<template>
  <div>
    <span>{{ result }}</span>
  </div>
</template>

<script>
import axios from 'axios'
export default {
  data () {
    return {
      result: ''
    }
  },
  mounted () {
    axios.get('http://<LaravelサーバのIP>/test1')
      .then((response) => {
        this.result = response.data.result
      })
      .catch((error) => {
        console.log(error)
        this.result = 'ERROR'
      })
  }
}
</script>

ブラウザからNuxt環境の上記ページを呼び出した直後に先に作成したLaravelのアクションを呼び出し、結果を画面に表示するという極めてシンプルな内容です。
これで実行してみましょう。
ERRORになります!
実は上記axiosの処理内容自体には問題がありません。しかし通信のルールに違反する状態が発生しているのです。
ブラウザの検証機能等で確認すると以下のようなエラーが出ているかと思います。

Access to XMLHttpRequest at 'http://<LaravelサーバのIP>/test1' from origin 'http://localhost:3000' has been blocked by CORS policy

CORSに関してはGoogle先生に聞きましょう。今回の環境においてはアクセス元の画面はlocalhost(Nuxtサーバ)から呼び出されたものであるのに対し、アクセス先はLaravelサーバです。これは最初の方で整理したように論理的には別サーバです。よってクロスオリジン状態にある訳です。
この場合、アクセスされるLaravel側でNuxtサーバから呼び出されたページからのアクセスを許容するような設定が必要になります。

CORS対応

クロスオリジン状態に対応するためにはレスポンスヘッダに相応の設定を行う必要があります。この処理はクロスオリジン状態で行われるアクションに共通するものであるため、Laravelのミドルウェアとして実装したいと思います。

php artisan make:middleware Cors

上記コマンド実行により「app/Http/Middleware/Cors.php」が生成されます。
中身は「handle」というメソッド1つですので、その中にレスポンスヘッダの設定処理を追加します。

public function handle($request, Closure $next)
{
    $response = $next($request);
    $response->withHeaders([
        'Access-Control-Allow-Origin' => '*',
    ]);
    return $response;
}

各種ネット情報ではもっと色々と設定していますが、最小限ということでは上記のみで成立するようです。そもそもがクロスオリジン状態において許容するアクセス元オリジンをどのように指定するかということが課題だったので当たり前のような気もしますが。
なお「*」は全てのオリジンからのアクセスを許容することを意味します。

上記で作成したミドルウェアはこれだけでは有効になりません。有効にするためには「app/Http/Kernel.php」に同ミドルウェアを登録する必要があります。なお、このミドルウェアはクロスオリジンでアクセスされるアクションに対してのみ必要となるものなので、選択的に適用できる「routeMiddleware」として登録します。

protected $routeMiddleware = [ 
    'auth' => \App\Http\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
    'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
    'can' => \Illuminate\Auth\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
    'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
    'cors' => \App\Http\Middleware\Cors::class, // ここに追加
];  

上記で「cors」という名称でミドルウェアを登録しましたので、「routes/web.php」を書き換えて同ミドルウェアを使用するグループを作成し、そのメンバとしてtest1アクションへのルートを定義するようにします。

Route::middleware(['cors'])->group(function () {
    Route::get('test1', 'TestController@test1');
});

これでNuxt環境から呼び出している画面を更新すると以下のように表示されるようになるかと思います。

Response from Laravel

めでたしめでたし。

次回予告

とりあえずNuxtのページからクロスオリジンでLaravelのアクションにGETでアクセスするという超基本的な動作は確認できました。
今後はPOSTでのアクセスを試したり、axios通信におけるセッション管理(cookieの扱い)に関しても触れて行きたいと思います。
今回はここまで。