目的
Cloud Internet Services(以下、CIS)はCloudflare社のサービスをIBM Cloud向けに提供しているものです。CISではGLBを定義してバックエンドのアプリケーションへのプロクシアクセスを実現しますが、もし、アプリケーションとの接続エラーが発生した場合、CISデフォルトのエラーページがクライアントに返ります。以下例です。
これですとあまりユーザーフレンドリーとは言えませんので、CISではカスタムページを使って、独自のコンテンツに置き換えることができます。
https://cloud.ibm.com/docs/infrastructure/cis?topic=cis-custom-page&locale=ja
しかし、上記ドキュメントに記載されていますが、
応答 500、501、503、および 505 は、特定の API エンドポイントおよび他の Web アプリケーションの中断を回避するために、カスタム・エラー・ページをトリガーしません。
となっており、肝心の一番出やすいアプリケーションのエラーに対しては、CISデフォルトのエラーページやカスタムページを使うことができません。この場合は、アプリケーションのエラー画面がそのままクライアントに返るようです。
そのとき、もしアプリケーションのエラー画面をユーザーフレンドリーにしたい場合はアプリケーション側で対応しなければいけませんが、アプリケーションの制約でエラー画面をカスタマイズできなかったり、できたとしても面倒なケースがあります。
そこで、今回はCISのEdge FunctionとCloud Object Storage(以下、COS)を使って簡単にSorryページを作ってみます。
前提
- Edge Functionを使うためにはCISのEnterprise以上のプランが必要です
- アプリケーションはすでにCISのGLB配下に設定されているものとします
手順
COSをオーダーする(略)
バケットを作成する(略)
バケットをパブリックアクセスにする
Sorryページのコンテンツをバケットに置く
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Sorry</title>
</head>
<body>
ごめん
</body>
</html>
CISでEdge Functionのアクションを登録する
const sorryUrl = "https://${バケット名}.s3.jp-tok.cloud-object-storage.appdomain.cloud/sorry.html";
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
let originalResponse = await fetch(request);
if (originalResponse.status >= 500) {
let sorryResponse = await fetch(sorryUrl);
return new Response(await sorryResponse.text(), {
status: originalResponse.status,
statusText: originalResponse.statusText,
headers: {
"Content-Type": "text/html; charset=utf-8"
}
});
} else {
return originalResponse;
}
}
アクションをトリガーで紐づける
テスト
アプリケーションで503エラーが出る状態にしておいて、
$ curl https://****************/****/ -v
(略)
> GET /****/ HTTP/1.1
> User-Agent: curl/7.29.0
> Host: ****************
> Accept: */*
>
< HTTP/1.1 503 Service Unavailable
< Date: Fri, 08 May 2020 19:51:01 GMT
< Content-Type: text/html; charset=utf-8
(略)
<
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Sorry</title>
</head>
<body>
ごめん
</body>
</html>
うまくいきました。
補足
当初はEdge Functionでコンテンツをフェッチするのではなく、単にバケットへのRedirectをしようとしていましたが、その場合、最終的なステータスコードが200になってしまうのと、レスポンスのContent-Typeがapplication/octet-streamになってしまうのでやめました。