Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
54
Help us understand the problem. What is going on with this article?
@amagurix

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

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>
54
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
amagurix
株式会社dotbind 代表取締役/CEO 兼フロントエンドエンジニア Nuxt.js, Gatsby,jsが好き React, Vue, Ruby, PHP, AWS... etc

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
54
Help us understand the problem. What is going on with this article?