はじめに
app routerでのapiを叩く際にエラーが出たので対処法を書きます。
問題
以下のようにapiを叩いた際にfetch errorが出る。localhostを直書きしても良いのですが、それだとvercel等にデプロイした際本番URLでエラーになるのでなんとかする必要があります。
page.tsx
import QiitaPage from './components/qiitaPage';
import MicrocmsPage from './components/microcmsPage';
export default async function Page() {
// 問題の行
const res = await fetch("/api/qiita", { cache: "no-store" });
const data = await res.json();
return (
<div className="px-5 py-5">
<QiitaPage data={data} />
<MicrocmsPage />
</div>
);
}
解決策
app routerの場合、絶対パスでapiリクエストを投げる必要があるみたいです。クライアント側でレンダリングさせれば相対パスでも書けるみたいですが、せっかくNext.jsを使っているのでサーバサイドでレンダリングさせたいです。なのでnext/headersから現状のプロトコルとホストを取得して利用します。先ほどのコードに少し追加します。
page.tsx
+ import { headers } from 'next/headers';
import QiitaPage from './components/qiitaPage';
import MicrocmsPage from './components/microcmsPage';
export default async function Page() {
// ホストとプロトコルを取得
+ const headersData = headers();
+ const protocol = headersData.get('x-forwarded-proto') || 'http';
+ const host = headersData.get('host');
// 絶対パスで指定してあげる
+ const apiBase = `${protocol}://${host}`;
+ const res = await fetch(`${apiBase}/api/qiita`, { cache: "no-store" });
// const res = await fetch("/api/qiita", { cache: "no-store" });
const data = await res.json();
return (
<div className="px-5 py-5">
<QiitaPage data={data} />
<MicrocmsPage />
</div>
);
}
おわりに
検索の仕方が悪く解決に少し時間がかかりました。
参考