Laravel Breeze(Next.js Edition)のパスワードリセットでエラー

はじめに

Laravel+Next.jsで、Auth認証を簡単に実装できる「Laravel Breeze – Next.js Edition」で開発中、パスワードリセットでエラーが出た時のメモ。

エラー内容

パスワードリセット画面で新しいパスワードを入力して送信後に以下のエラーが出た。

Unhandled Runtime Error
TypeError: error.response is undefined

error.responseundefinedとの事だが、API(Laravel)では正しく処理されてちゃんとレスポンスを返している。問題の部分のコードを抜粋すると、

src/hooks/auth.js

axios
    .post('/reset-password', { token: router.query.token, ...props })
    .then(response => router.push('/login?reset=' + btoa(response.data.status)))
    .catch(error => {
        if (error.response.status != 422) throw error

        setErrors(Object.values(error.response.data.errors).flat())
    })

.catch()でキャッチしたエラーはサーバ側ではなく、一つ上の行の.then()内のbtoa()関数がエラーを吐いていた。

原因

原因は、btoa()関数の引数に日本語を渡していたのが原因でした。(btoa()関数は日本語非対応)

Laravel Breezeのレスポンスメッセージは元々英語ですが、resources/lang/jaで日本語にカスタマイズをしていたので、response.data.statusstatusに日本語が入っていたんですね。

対策

日本語は活かしたいので、btoa()関数を別のエスケープ関数に置き換えました。

src/hooks/auth.js

axios
    .post('/reset-password', { token: router.query.token, ...props })
    //.then(response => router.push('/login?reset=' + btoa(response.data.status)))
    .then(response => router.push('/login?reset=' + encodeURIComponent(response.data.status)))
    .catch(error => {
        if (error.response.status != 422) throw error

        setErrors(Object.values(error.response.data.errors).flat())
    })

btoa()関数と同様の処理をする方法(複数の関数組み合わせ)もありましたが、デコードがうまくいかなかったので、今回はencodeURIComponent()関数のみで代用。

これでエラーは出ず、パスワードリセットされ移動先のログインページに画面遷移されました。

ログインページでは先程のstatusをクエリで受け取って表示するようになっています。ここでデコード処理をしないと文字化けしますので、statusをセットする所で以下のようにデコード。

src/pages/login.js

useEffect(() => {
    if (router.query.reset?.length > 0 && errors.length === 0) {
        //setStatus(atob(router.query.reset))
        setStatus(decodeURIComponent(router.query.reset))
    } else {
        setStatus(null)
    }
})

atob()関数をdecodeURIComponent()関数に置換。

まとめ

以上で日本語のレスポンスメッセージでもエラーが出ず正しく表示されました。encodeURIComponent()関数で代用が正しいか微妙ですが、動いているので良しとします(;´∀`)