curlに-Lを付けずに308を叩くと15バイトの「Redirecting...」が返る──sitemapが0件・サイトが壊れたと誤診する罠
apex→wwwの308恒久リダイレクトを -L なしのcurlで叩くと、返るのは空ボディではなく Redirecting...(改行込み15バイト、Content-Type: text/plain)だった。そのため grep -c '<loc>' は0件、記事HTMLは15バイト、canonicalもJSON-LDも0件になり、sitemapが空・SSGが壊れたと3つまとめて誤診しうる。-L を付け直すと同じURLが200・125455バイト・<loc> 416件で、全部正常だった。2026-08-14にcurl 8.7.1 / macOS 15.1.1で再現した記録。
結論から書く。apexドメイン(ai-jitan-hub.com)から www へ308でリダイレクトされるURLを -L なしの curl で叩くと、返ってくるのは空ボディではなく Redirecting... の15バイトだ。Content-Type は text/plain。だから grep -c '<loc>' は0を返し、HTMLを取れば「15バイト」になり、canonicalもJSON-LDも0件になる。sitemapが空なのでもSSGが壊れたのでもない。リダイレクトを追わない診断コマンドが、壊れていないものを壊れていると報告している。直し方は一つ、curl -sL にする。それだけで同じURLが200・125455バイト・<loc> 416件になった(2026-08-14、当サイト本番で確認)。
3行まとめ
- apex→wwwの308を
-Lなしで叩くと、ボディは空ではなくRedirecting...(改行込み15バイト、Content-Type: text/plain)が返る- その15バイトを解析すると、
<loc>0件・HTML 15バイト・canonical 0件・JSON-LD 0件が同時に出て、「sitemapが空」「SSGが壊れた」「メタデータが飛んだ」と一式で誤診するcurl -sLに直すと同じURLが200・125455バイト・<loc>416件。壊れていたのはサイトではなく診断コマンドだった
症状
貼って検索されるのはこの文字列だと思うので、コマンドと出力をそのまま置く。
$ curl -s https://ai-jitan-hub.com/sitemap.xml
Redirecting...
$ curl -s -o /tmp/s.txt -w 'code=%{http_code} size=%{size_download}\n' https://ai-jitan-hub.com/sitemap.xml
code=308 size=15
$ xxd /tmp/s.txt
00000000: 5265 6469 7265 6374 696e 672e 2e2e 0a Redirecting....
$ grep -c '<loc>' /tmp/s.txt
0
15バイトの内訳は Redirecting... の14文字と、末尾の改行(0a)1バイト。
レスポンスヘッダは次の通り(抜粋、2026-08-14取得)。
HTTP/2 308
content-type: text/plain
location: https://www.ai-jitan-hub.com/sitemap.xml
refresh: 0;url=https://www.ai-jitan-hub.com/sitemap.xml
server: Vercel
厄介なのは、症状がsitemapだけに出ないことだ。同じ308が全パスに掛かっているので、記事ページを叩いても15バイトが返る。2026-08-14に実際に出た値を並べる。
| 実行したこと | -L なしで出た結果 |
その値だけを見て下しうる誤った診断 | -L ありの実際 |
|---|---|---|---|
sitemap.xml を取得して grep -c '<loc>' |
code=308 / size=15 / 0件 | sitemapが空。記事が1本も載っていない | code=200 / size=125455 / 416件 |
| 記事ページのHTMLを取得 | code=308 / size=15 | HTMLが15バイト。SSGのビルドが壊れた | code=200 / size=211626 |
同ページで grep -c 'rel="canonical"' |
0件 | canonicalが出力されていない | 1件 |
同ページで grep -c 'application/ld+json' |
0件 | 構造化データが全部飛んだ | 2件 |
| トップページを取得 | code=308 / size=15 | サイト全体が死んでいる | (同じく308→www側で200) |
4つの「壊れている証拠」が同時に出るので、かえって確信してしまう。原因は1つで、しかもサイト側ではない。
原因
噛み合っているのは3つ。
1. 308はボディを返してはいけない、とは書かれていない
MDNの308の説明はこうだ。
The HTTP 308 Permanent Redirect redirection response status code indicates that the requested resource has been permanently moved to the URL given by the Location header. A browser receiving this status will automatically request the resource at the URL in the Location header, redirecting the user to the new page.
(訳:HTTP 308 Permanent Redirect は、要求されたリソースが Location ヘッダで示されたURLへ恒久的に移動したことを示すリダイレクト応答ステータスコードである。このステータスを受け取ったブラウザは、Location ヘッダのURLのリソースを自動的に要求し、ユーザーを新しいページへリダイレクトする。)
主語が「A browser」であることに注意したい。自動的に追いかけるのはブラウザの振る舞いとして書かれているのであって、あらゆるHTTPクライアントがそうする、とは書かれていない。
同ページの応答例は Content-Length: 0(空ボディ)になっている。だが、これは例であって「ボディを空にせよ」という規定ではない。実際、当サイトのホストが返してきたのは15バイトのボディだった。「308なら空バイトのはず」という先入観が、15バイトを「壊れた応答」に見せる。
2. curlは -L を付けない限り追わない
curlのman pageの -L, --location はこう説明している。
(HTTP) If the server reports that the requested page has moved to a different location (indicated with a Location: header and a 3XX response code), this option makes curl redo the request to the new place.
(訳:(HTTP)要求されたページが別の場所へ移動したとサーバが報告した場合(Location: ヘッダと3XX応答コードで示される)、このオプションはcurlに新しい場所への再要求を行わせる。)
つまり -L は「リダイレクトを追う」オプションではなく、付けなければ追わないのが既定ということだ。ブラウザで開けば正常に見えるのに、curlのワンライナーだけが壊れて見える理由がここにある。ブラウザとcurlで既定の振る舞いが違う。
3. その308を出しているのは自分の設定ファイル
当サイトの next.config.ts の redirects() に、apexへのアクセスをwwwへ寄せる規則が入っている(以下は該当箇所の抜粋。同ファイルには他の記事URL向けリダイレクトも並んでいる)。
async redirects() {
return [
{
source: "/:path*",
has: [{ type: "host", value: "ai-jitan-hub.com" }],
destination: "https://www.ai-jitan-hub.com/:path*",
permanent: true,
},
];
}
permanent: true が308になる根拠は、手元にインストールされている next 16.2.7 の同梱ドキュメント(node_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/redirects.md)に明記されている。
permanenttrueorfalse- iftruewill use the 308 status code which instructs clients/search engines to cache the redirect forever, iffalsewill use the 307 status code which is temporary and is not cached.(訳:
permanentはtrueかfalse。trueなら308ステータスコードを使い、クライアントや検索エンジンにそのリダイレクトを永久にキャッシュするよう指示する。falseなら307で、これは一時的でキャッシュされない。)
ホストで振り分ける has の書き方も同ドキュメントにある。
type:String- must be eitherheader,cookie,host, orquery.(訳:
typeは文字列で、header・cookie・host・queryのいずれかでなければならない。)
さっきのヘッダに refresh: 0;url=... が混じっていたのも、同ドキュメントに書かれている。
To ensure IE11 compatibility, a
Refreshheader is automatically added for the 308 status code.(訳:IE11との互換性を確保するため、308ステータスコードには
Refreshヘッダが自動的に付与される。)
なお、ボディの Redirecting... という文字列そのものは、この同梱ドキュメントにもMDNにも記載がない。node_modules/next/dist/ を Redirecting... でgrepしても、ヒットしたのはドキュメント内のJSXサンプル(return <p>Redirecting...</p>)だけで、実行コードには無かった。応答の server: Vercel から配信側が組み立てた文字列だと考えているが、これは確認できていない推測である(後述の但し書き参照)。
対処
① 追う:-L を付ける
$ curl -sL -o /tmp/s.txt -w 'code=%{http_code} size=%{size_download} url_effective=%{url_effective}\n' https://ai-jitan-hub.com/sitemap.xml
code=200 size=125455 url_effective=https://www.ai-jitan-hub.com/sitemap.xml
$ grep -c '<loc>' /tmp/s.txt
416
%{url_effective} を出力に足しておくと、「自分が今どのURLの中身を見ているのか」が毎回目に入る。man pageの定義はこうだ。
url_effective— The URL that was fetched last. This is most meaningful if you have told curl to follow location: headers.(訳:
url_effective— 最後に取得されたURL。curlに location: ヘッダを追うよう指示している場合に最も意味を持つ。)
② 追わずに気づく:%{redirect_url} を出力に足す
リダイレクトを追いたくない診断(ステータスコードだけ見たい場合など)でも、飛び先を表示すれば誤診は防げる。
$ curl -s -o /dev/null -w 'http_code=%{http_code} redirect_url=%{redirect_url}\n' https://ai-jitan-hub.com/sitemap.xml
http_code=308 redirect_url=https://www.ai-jitan-hub.com/sitemap.xml
redirect_url— When an HTTP request was made without --location to follow redirects (or when --max-redirs is met), this variable shows the actual URL a redirect would have gone to.(訳:
redirect_url— リダイレクトを追う --location なしでHTTP要求が行われた場合(または --max-redirs に達した場合)、この変数はリダイレクトが実際に向かうはずだったURLを示す。)
③ チェーンを目視する:curl -sIL
$ curl -sIL https://ai-jitan-hub.com/sitemap.xml | grep -iE '^HTTP|^location|^content-type'
HTTP/2 308
content-type: text/plain
location: https://www.ai-jitan-hub.com/sitemap.xml
HTTP/2 200
content-type: application/xml
content-type が text/plain から application/xml に変わるところまで見えると、1本目が中身ではないことが一目で分かる。
④ そもそも最終ホストを叩く
$ curl -s -o /dev/null -w 'http_code=%{http_code} size=%{size_download}\n' https://www.ai-jitan-hub.com/sitemap.xml
http_code=200 size=125455
運用として一番効いたのはこれだった。サイトを点検するスクリプトやワンライナーのベースURLを、リダイレクト元ではなく最終ホスト(当サイトなら https://www. 側)で持つ。-L を付け忘れても壊れなくなる。
観測条件
- 日付: 2026-08-14。応答ヘッダの
dateはFri, 14 Aug 2026 05:59:30 GMT - 環境: macOS 15.1.1(BuildVersion 24B91)/
/usr/bin/curlは curl 8.7.1(x86_64-apple-darwin24.0)、libcurl/8.7.1、nghttp2/1.62.0 - 対象: 当サイトの本番(
server: Vercel、Next.js 16.2.7、apex→wwwの308はnext.config.tsのredirects()由来) - 再現: 本記事に載せたコマンドは、記事を書く時点で同日中に全て再実行し、同じ値が出ることを確認して数字を採った。
<loc>416件・sitemap 125455バイト・記事ページ211626バイトは、その再実行時点の実測値
ここで効く判断はひとつだ。ブラウザで開けば普通に表示されるのに、curlのワンライナーだけが0件を返す。その食い違いが出た時点で、まず疑うべきはサイトではなくコマンドの側になる。
正直な但し書き
- ボディ文字列
Redirecting...の出所を公式に確認できていない。 next 16.2.7 の同梱ドキュメントにもMDNにも記載はなく、node_modules/next/dist/のgrepでも実行コードには無かった。応答のserver: Vercelから配信側の挙動だと推測しているが、推測であって確認された事実ではない - ローカルの
next startで同じ15バイトが返るかは未検証。 本記事の観測はすべてVercel配信の本番ホストに対するもので、ローカルサーバでの再現は試していない - バイト数はサイトの中身が増減すれば変わる。 125455バイト・211626バイト・
<loc>416件を固定値として引用しないでほしい。再現性があるのは「-Lなしで308を叩くと15バイトのRedirecting...が返り、grepが0件になる」という構造の方である - 308を返すサーバが全てこのボディを返すわけではない。 MDNの例は
Content-Length: 0の空ボディだ。空ボディを返す構成なら症状は「0バイト」になり、Redirecting...という文字列は出ない。その場合でも「grepが0件になる」誤診自体は同じように起きる - 多段リダイレクトは検証していない。 当サイトのリダイレクトはapex→wwwの1ホップだけで、
--max-redirsに当たるケースや複数回転送される構成での挙動は確認していない - curlの引用は curl.se の最新man pageから取っており、手元の 8.7.1 の文面とは細部が違う。
-Lの説明は最新版が「redo the request to the new place」、手元の curl 8.7.1 の man page は「redo the request on the new place」。redirect_urlも最新版が「without --location」、8.7.1 は「without -L, --location」と表記が異なる。意味は変わらないが、引用は最新版の文面である - 診断時のコマンドログは保存していない。 本記事の数値は執筆時点で全て再実行して取り直したものであり、再現できるのは「
-Lなしで308を叩くと何が返るか」までである。当日どういう順番で何を勘違いしたかについては、記録として残しているものが無い - 本記事は当サイト1ドメイン・1環境での観測であり、他のホスティングや他のcurlバージョンで同じ文字列・同じバイト数になることを保証するものではない
出典
- MDN Web Docs「308 Permanent Redirect」 — https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/308(2026-08-14取得)
- curl man page(
-L, --location、--write-outのredirect_urlおよびurl_effective) — https://curl.se/docs/manpage.html(2026-08-14取得) - Next.js
redirects設定ドキュメント — https://nextjs.org/docs/app/api-reference/config/next-config-js/redirects(2026-08-14取得)。本記事の引用は、当リポジトリのAGENTS.mdの指示に従い、手元にインストールされた next 16.2.7 の同梱ドキュメントnode_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/redirects.mdから取っている。引用した3文が同日時点の公開ドキュメントとも一致することは確認した
出典・参照資料
- 一次資料MDN Web Docs — 308 Permanent Redirect(HTTP response status codes) ↗
- 一次資料curl man page — -L, --location および --write-out の redirect_url / url_effective ↗
- 一次資料Next.js redirects 設定ドキュメント(引用は手元にインストールされた next 16.2.7 同梱の node_modules/next/dist/docs/01-app/03-api-reference/05-config/01-next-config-js/redirects.md から取得。同日時点の公開版とも一致を確認) ↗
AIニュースの解説を動画でも
YouTubeでは注目ニュースの背景を解説し、Xでは新着記事をお知らせしています。
コメント
まだコメントはありません。最初のコメントを書いてみませんか?
AIについて聞きたいことはありますか?
質問箱で無料で受け付けています。回答は公開され、他の方の参考にもなります。
質問箱を見る →新しい記事をメールで受け取る
AIの新しい発表を、出典付きで整理して届けます。