NUXT.js로 SSR 할 때의 함정

NUXT.js×REST API×Typescript×SSR



NUXT.js는 SSR의 설정 자체는 mode: 'universal', 합니다.
상당히 빠져서 메모.

문제



SSR시에만 API 응답을 얻을 수 없다.



SPA 때는 API 응답이 제대로 돌아와서 문제 없지만,
SSR시에는 요청은 되었지만 API 응답이 반환되지 않는 오류가 발생했습니다.

원인



SSR하는 경우 asyncData 라이프 사이클에서 API를 요청해야한다고 생각합니다.
그 때, proxy라든지를 사용하고 있으면 SSR시만 API 취득을 할 수 없습니다.
nuxt-link의 전환이라면 잘 작동하지만 화면을 다시로드하면 오류가 발생하는 것 같습니다.

※SSR일 때는 proxy를 사용할 필요가 없습니다.

해결



axios의 baseURL을 브라우저시와 SSR시로 나눌 뿐이었다
baseURL: process.browser ? '' : ‘https://api.endpoint.com’
process.browser 는 nuxt라면 디폴트로 취득할 수 있습니다.

이번은 아래와 같은 모듈을 사용하고 있는 전제입니다.
- axios (axios-module을 사용하지 않고 axios를 사용하고 싶습니다)
- @nuxt/proxy

※ axios-module을 사용하지 않는 이유는 아래 기사와 같은 이유
replace axios-module to axios - axios-module을 axios로 대체했습니다.

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

아래는 보충



@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>

좋은 웹페이지 즐겨찾기