最近個人開発しているアプリでは、@remix-run/node
のfetch()
を使って特定のURLのメタ情報を取得するようにしていました。
あるとき、https://engineerteam.note.jp/n/nb49d32f5bede
に対してfetch()
を呼び出す機会がありました。
const response = await fetch(url);
ところが、これを呼び出してみたところPremature close
というエラーが発生してしまいました。
/workspaces/example-app/node_modules/@remix-run/web-fetch/src/fetch.js:342
const error = Object.assign(new Error('Premature close'), {
^
Error: Premature close
at TLSSocket.onSocketClose (/workspaces/example-app/node_modules/@remix-run/web-fetch/src/fetch.js:342:33)
at TLSSocket.emit (node:events:525:35)
at node:net:301:12
at TCP.done (node:_tls_wrap:588:7)
色々オプションを設定してみましたが、エラーの発生を防ぐことはできませんでした。
const response = await fetch(url, {
method: "GET",
redirect: "follow",
follow: 10,
});
調べてみても、同じような問題に引っ掛かっている人がいないため、なかなか答えを見つけられませんでした。
そこで、これはfetch()
特有の問題なのかと思い、試しにaxios
を使ってみることにしました。
import axios from 'axios'
...
const res = await axios.get(url)
今度はより詳細なエラーが発生しました。
内容を確認してみると、リダイレクトの回数が多すぎるということがわかりました。
おそらく、fetch()
でもこの問題が発生しているためPremature close
というエラーが発生していたのだと思います。
Error [ERR_FR_TOO_MANY_REDIRECTS]: Maximum number of redirects exceeded
at Function.AxiosError.from (/workspaces/example-app/node_modules/axios/lib/core/AxiosError.js:89:14)
at RedirectableRequest.handleRequestError (/workspaces/example-app/node_modules/axios/lib/adapters/http.js:577:25)
at RedirectableRequest.emit (node:events:513:28)
at RedirectableRequest._processResponse (/workspaces/example-app/node_modules/follow-redirects/index.js:371:10)
at NodeClientRequest.RedirectableRequest._onNativeResponse (/workspaces/example-app/node_modules/follow-redirects/index.js:62:10)
より詳細なエラーの内容がわかったので、これをもとに色々調べてみると、こちらの投稿を見つけました。
投稿者の方が抱えていた問題の原因は、サーバー側によるクッキーを使ったステートの検証によるリダイレクトのループの発生のようです。
つまり、リクエスト先のサーバー側で、本来ならクエリーとして渡すべき情報をクッキーによって管理しているため、そのデータの有無により永遠にリダイレクトされるといった問題のようです。
つまり、ここで必要なのはCookie Jarの機能ということになります。
Cookie Jarとは、簡単にいうと、特定のウェブサイトのクッキーを保存・管理するためのコンテナ機能のことです。
この機能がNode.jsで動作するaxios
やfetch()
ではデフォルトでサポートされていないため、何も設定しない状態でリクエストを送っても先ほどのようなエラーが発生してしまいます。
そこで、この問題を解決するためにaxios-cookiejar-support
というライブラリを使うことにしました。
今回、axios
を使うにあたってレスポンスとして文字列ではなくArrayBuffer
としてデータを取得する必要があるため、responseType: "arraybuffer"
を指定しています。
const jar = new CookieJar();
const client = wrapper(axios.create({ jar }));
const result = await client.get(url, {
maxRedirects: 10,
responseType: "arraybuffer",
});
実行した結果、無事エラーがでることなくレスポンスを取得することに成功しました。
リダイレクトループにハマってから原因を特定するまでに結構な時間を要してしまいました。
そもそも、何が原因でPremature close
エラーが発生しているのかわからなかったためです。
みなさまも、同じような問題に遭遇した際は、クッキーの問題かどうかを考えてみると良いかもしれません。