はじめに
ウェブ開発において、異なるオリジン間でのデータのやり取りは一般的ですが、クロスオリジンリクエストに関連するCORS(クロスオリジンリソース共有)エラーに悩まされることがあります。この記事では、Next.jsを用いてサーバーサイドからリクエストを送ることでCORSエラーを回避する方法を紹介します。
CORSとは
CORS(クロスオリジンリソース共有)は、ウェブブラウザが異なるオリジン(ドメイン、ポート、またはプロトコル)からのリクエストを制限するセキュリティ機能です。クライアントサイドからサーバーにリクエストを送信する際、ChromeなどのブラウザはサーバーからのレスポンスにAccess-Control-Allow-Origin
ヘッダーが含まれているかどうかをチェックします。もし、このヘッダーが存在しないか、リクエスト元のオリジンが許可されていない場合、CORSエラーが発生し、リクエストはブロックされます。
参考にしたもの
ブラウザからサーバーにアクセスすると
ステップ 1: クライアント(ブラウザ)リクエスト
ブラウザがクロスオリジンリクエストを行うと、ブラウザはOrigin
ヘッダーを現在のオリジン(スキーム、ホスト、ポート)とともに追加します。
ステップ 2: サーバーレスポンス
サーバーがこのヘッダーを確認し、アクセスを許可すると、リクエスト元のオリジンを指定するAccess-Control-Allow-Origin
ヘッダーをレスポンスに追加します(または、任意のオリジンを許可する場合は*
)。
ステップ 3: ブラウザがレスポンスを受信する
ブラウザは、適切なAccess-Control-Allow-Origin
ヘッダーを含むこのレスポンスを確認すると、レスポンスデータをクライアントサイトと共有します。
問題が発生した事例
今回は、環境省のウェブサイトからCSVデータを取得しようとした際に、クライアントサイドでCORSエラーが発生しました。おそらく、環境省のサーバーがAccess-Control-Allow-Origin
ヘッダーを含めていなかったため、ブラウザがリクエストを拒否したと思われます。
環境省 暑さ指数(WBGT)予測値等 電子情報提供サービス
対応方法
Next.jsのサーバーサイドから環境省のウェブサイトにリクエストすることにしました。Next.jsなどのサーバーサイド環境からリクエストを送る場合、ブラウザのCORSチェックが適用されません。これにより、環境省のサーバーがAccess-Control-Allow-Origin
ヘッダーを含んでいなくても、問題なくデータを取得できます。
ファイル構成
my-next-app/
├── package.json
├── tsconfig.json
├── next.config.js
├── src/
│ ├── pages/
│ │ ├── index.tsx
│ │ └── api/
│ │ └── wbgt.ts //サーバーサイドからのリクエスト用ファイル
└── (その他の設定ファイルやディレクトリ)
サーバーサイドからのリクエスト
import axios from 'axios'
export default async function handler(req: any, res: any) {
const AREA_CODE = '44132' // 東京の地点コード
try {
const response = await axios.get(
`https://www.wbgt.env.go.jp/prev15WG/dl/yohou_${AREA_CODE}.csv`,
)
const data = response.data
res.status(200).json({ data })
} catch (error) {
console.error('CSVデータの取得に失敗しました', error)
res.status(500).json({ error: 'CSVデータの取得に失敗しました' })
}
}
参考 API Routeについて
クライアントサイドでの利用
import { useEffect, useState } from 'react'
import axios from 'axios'
const Index = () => {
const [data, setData] = useState(null)
useEffect(() => {
const fetchData = async () => {
try {
const response = await axios.get('/api/wbgt')
setData(response.data)
console.log(data) //コンソール画面に取得したdataを表示
} catch (error) {
console.error('データの取得に失敗しました', error)
}
}
fetchData()
}, [])
return (
<div>
<h1>WBGTインデックス</h1>
</div>
)
}
export default Index
クライアントサイドでは、このAPIルートに対してリクエストを送信し、取得したコンソール画面に表示しています。
結論
ブラウザのCORS制約は、クライアントサイドのセキュリティを強化するための重要な機能ですが、開発中にエラーを引き起こすことがあります。Next.jsなどのサーバーサイドでのリクエストを利用することで、これらの制約を回避し、安全にデータを取得する方法を紹介しました。