fetch API を使用してリクエストを行う際、サーバーからのレスポンスがエラー(例えば、HTTPステータスコードが 4xx や 5xx)であっても、サーバーから返されるレスポンスボディ(エラーメッセージなど)を取得することが可能です。以下に、その方法について詳しく説明します。
基本的な考え方
- レスポンスのステータスを確認する:
fetch
はネットワークエラーの場合のみPromise
を拒否(reject)します。HTTPステータスがエラー(例: 404, 500)でも、Promise
は解決(resolve)されます。- したがって、レスポンスの
ok
プロパティをチェックして、成功かエラーかを判定する必要があります。
- エラーレスポンスのボディを取得する:
- エラー時でもサーバーがレスポンスボディを返している場合、それをパースして詳細なエラーメッセージなどを取得できます。
- エラーハンドリング:
async/await
とtry...catch
を使用すると、非同期処理のエラーハンドリングが簡潔に記述できます。
実装例
以下は、fetch
リクエストでエラーが発生した際に、エラーレスポンスのボディを取得する方法の具体例です。
1. async/await を使用した例
async function fetchData(url, options) {
try {
const response = await fetch(url, options);
// レスポンスのステータスを確認
if (!response.ok) {
// エラーレスポンスの Content-Type を取得
const contentType = response.headers.get('content-type');
let errorData;
if (contentType && contentType.includes('application/json')) {
// JSON 形式の場合
errorData = await response.json();
} else {
// テキスト形式の場合
errorData = await response.text();
}
// エラーデータを含むエラーをスロー
throw new Error(JSON.stringify({
status: response.status,
statusText: response.statusText,
data: errorData
}));
}
// レスポンスが正常な場合、データをパースして返す
const data = await response.json();
return data;
} catch (error) {
// エラーハンドリング
console.error('Fetch error:', error);
try {
// スローされたエラーが JSON 形式の場合、パースする
const errorObj = JSON.parse(error.message);
console.log('エラーのステータス:', errorObj.status);
console.log('エラーのステータステキスト:', errorObj.statusText);
console.log('エラーデータ:', errorObj.data);
} catch (e) {
// エラーメッセージが JSON でない場合
console.log('エラーメッセージ:', error.message);
}
}
}
// 使用例
fetchData('https://api.example.com/data', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
});
2. then/catch を使用した例
function fetchData(url, options) {
return fetch(url, options)
.then(async (response) => {
if (!response.ok) {
const contentType = response.headers.get('content-type');
let errorData;
if (contentType && contentType.includes('application/json')) {
errorData = await response.json();
} else {
errorData = await response.text();
}
// エラーデータを含むオブジェクトを返す
return Promise.reject({
status: response.status,
statusText: response.statusText,
data: errorData
});
}
// 正常なレスポンスの場合、データを返す
return response.json();
})
.then(data => {
console.log('データ:', data);
})
.catch(error => {
console.error('Fetch error:', error);
console.log('エラーのステータス:', error.status);
console.log('エラーのステータステキスト:', error.statusText);
console.log('エラーデータ:', error.data);
});
}
// 使用例
fetchData('https://api.example.com/data', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
});
詳細な説明
- レスポンスのステータス確認:
response.ok
は、レスポンスのステータスが 200 ~ 299 の範囲内であればtrue
を返します。それ以外の場合はfalse
となります。- これを利用して、レスポンスが成功かエラーかを判定します。
- エラーレスポンスのパース:
Content-Type
ヘッダーをチェックして、レスポンスボディの形式を判断します。- JSON 形式の場合は
response.json()
を使用し、テキスト形式の場合はresponse.text()
を使用してパースします。
- エラーハンドリング:
throw
文を使用してエラーをスローすることで、catch
ブロックでエラーをキャッチできます。- エラーメッセージが JSON 形式であれば、さらに詳細な情報を取得できます。
- 注意点:
- サーバーがエラーレスポンスで返すデータの形式(JSON、テキストなど)を事前に確認し、それに応じてパース方法を選択してください。
- ネットワークエラーの場合、
fetch
はTypeError
をスローします。これも適切にハンドリングする必要があります。
まとめ
fetch
リクエストでエラーが発生した際にも、サーバーから返されるエラーレスポンスのボディを取得して詳細な情報を得ることが可能です。レスポンスのステータスを確認し、エラーレスポンスを適切にパースすることで、エラーハンドリングをより効果的に行うことができます。上記の実装例を参考に、プロジェクトに合わせたエラーハンドリングを実装してください。