概要
学習用のフォルダでQueueについて実装したところ、500と405のエラーが発生した。
実装パターン
Laravel(API)で「メモ一覧をテキストファイルに書き出す処理」を非同期ジョブとして実行し、React(SPA)で「ジョブの進捗と結果URL」を表示できる画面を作成していた。
発生したエラーの原因について
1. ログイン周りで発生したエラー(500)について
LaravelがHTTPS:443で待っていたにも関わらずVite proxyがHTTP(80相当)に投げていたためtargetのズレが発生していた
実際の原因はバックエンドの500ではなく、Viteのproxy転送失敗(socket hang up)だった。
ブラウザ上は 500 に見えるが、Laravelに到達する前に接続が切れていた。
2. エクスポート開始で405のエラー
フロント側のリクエストメソッドがLaravelのルート定義と一致していなかった。
エクスポート処理のためLaravel側で
Route::post('/memos/export',[MemoController::class, 'export']);
と記述したにも関わらず、React側でpost通信の実装がされていなかった
3. ファイルURLで ERR_EMPTY_RESPONSE / Empty reply が発生
Laravelはhttps:443で配信しているのに、APP_URL 由来で生成されたresult_urlがhttpになっており、ブラウザで`http側へアクセスしてしまった。
それぞれの解決方法
1. Vite の proxy 修正
下記のようにtargetをhttp:80からhttps:443に修正
export default defineConfig({
// 省略
server: {
proxy: {
"/api":{
target: "https://localhost:443",
changeOrigin: true,
secure: false,
},
},
},
// 省略
2. Reactの実装内容修正
sail artisan route:listコマンドを実行し確認することでLaravel側ではPOST通信されていることを確認
その後、React側で実装内容が誤っていたので下記のように修正した。
修正前ではmethodの指定がなかったためGET通信を行なっていたことが原因だった。
// 修正前 (method指定なしのためGET扱い)
return apiRequest('/memos/export');
// 修正後
export function startMemosExport() {
return apiRequest('/memos/export', { method: 'POST' });
}
3. httpsで確認する
対象のページについてhttpで確認していたところを、httpsで開き無事ページを確認することができた。
その他の対応
APIクライアントに対して認証ヘッダを付与する対応
修正前のapiClient.jsxでは認証ヘッダが付与されていなかった。
そこでapiClient.jsxに対して実装内容を追加し修正した。
import { getToken } from '../lib/api';
const BASE_URL = import.meta.env.VITE_API_BASE_URL;
export async function apiRequest(path, { method = 'GET', body, signal } = {}) {
const url = `${BASE_URL}${path}`;
const token = getToken();
const headers = {
'Content-Type': 'application/json',
};
if (token) headers.Authorization = `Bearer ${token}`;
// 省略
}
この実装の目的は、ログインで取得したトークンを以降のAPI呼び出しに必ず付けて 「認証済みユーザー」として扱ってもらうためである
この実装を行わないことで、認証が必要なAPI全て失敗してしまうことや今回の実装においてジョブの監視が止まらない状態になってしまう。
これはLaravel側のAPIがauth:sanctum や Bearer トークン前提だとAuthorization が無いリクエストは401や403エラーが発生してしまい、ジョブを取得するAPIがずっと401で失敗しステータスが変わらないために発生してしまう。