LoginSignup
67

More than 1 year has passed since last update.

NUXT.jsでSSRする場合の落とし穴

Last updated at Posted at 2019-08-01

NUXT.js×REST API×Typescript×SSR

NUXT.jsはSSRの設定自体はmode: 'universal', とするだけでいいのですが、SSRとSPAで気を使って実装しないと、データの取得などで、どっちかでは動く、動かない問題が出てきます。
結構ハマったのでメモ。

:skull: 問題

SSR時だけAPIレスポンスが取得できない。

SPA時はAPIレスポンスがちゃんと返ってきて問題ないのだが、
SSR時はリクエストはされているのに、APIレスポンスが返ってこないようなエラーが起こった。

:zap: 原因

SSRする場合、asyncDataのライフサイクルでAPIのリクエストをする必要があると思います。
その時、proxyとかを使っているとSSR時のみAPI取得ができません。
nuxt-linkの遷移ならうまくいくのに、画面リロードしたらエラーでるみたいなケースです。

※SSRのときはproxyを使う必要がありません。

:tada: 解決

axiosのbaseURLをブラウザ時とSSR時で分けるだけだった
baseURL: process.browser ? '' : ‘https://api.endpoint.com’

process.browser はnuxtならデフォルトで取得できます。

今回は下記モジュールを使っている前提です。
- axios(axios-moduleを使わずaxiosを使いたい)
- @nuxt/proxy

※ axios-moduleを使わない理由は下記記事と同様の理由
:fire: replace axios-module to axios - axios-moduleをaxiosにreplaceしたはなし

APIクライアント

/plugins/api/utils/clinet.ts

import axios from 'axios'

const instance = axios.create({
  baseURL: process.browser ? '' : process.env.API_HOST, //←これを追加。ブラウザのときは 空 もしくは/apiから始まるようにしないとproxyが効かずフロントから取得できないです。
  withCredentials: process.env.NODE_ENV !== 'production',
  headers: {
     'X-Requested-With': 'XMLHttpRequest',
     'Access-Control-Allow-Origin': '*'
  },
  timeout: 20000
})
export const client = instance

:raising_hand:下記は補足

@nuxt/proxyの設定

$ yarn add @nuxt/proxy でインストールして

nuxt.config.ts

const config: NuxtConfiguration = {
  mode: 'universal',

  modules: [
     '@nuxtjs/proxy'
  ],
  proxy: { //  /apiで始まるアクセスを http://docker.for.mac.localhost(APIサーバーのエンドポイント)に置き換える
    '/api': {
      target: ` http://docker.for.mac.localhost`,
      changeOrigin: true,
      pathRewrite: {
        '^/api/': '/api/'
      }
    }
  }
}

APIメソッド

/plugins/api/auth.ts

import { client as httpClient } from '@/plugins/api/utils/client'

// import types
import * as types from '@/types/AuthUser'

/**
 * api/auth_user
 * @param null
 */
export const getAuthUser = () => {
  return httpClient
    .get<types.GetAuthUserResponse>(`/api/auth_user`)
    .then((response) => response)
}

API型定義

/types/AuthUser.ts

export interface AuthUser {
  id: number
  name: string
  token: string
}

export interface GetAuthUserResponse {
  data: {
    authUser: AuthUser
  }
}

APIの呼び出し

pages/index.vue


<script lang="ts">
import { Component, Vue } from 'nuxt-property-decorator'
import { AuthUser } from '@/types/AuthUser'
import { getAuthUser } from '@/plugins/api/auth'

@Component
export default class Index extends Vue {
  authUser!: AuthUser

  async asyncData({ app, error }) {
    const result = await getAuthUser()
      .then((res) => {
        return { authUser: res.data.auth_user }
      })
      .catch((e) => {
        console.log(e)
        error({
          statusCode: 500,
          message: 'サーバー側でエラーが発生しました'
        })
        return
      })
    return result
  }
}
</script>

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
67