# Cloudfront 周りでの問題点
前提の共有:
- 全体像

- フロントエンド周りの抜粋

- フロントエンド周りで、関連サービスで言うと、(Cloudfront Function, Cognito, S3)が関わる部分についてご教授頂けたらと思います。
ゴール:
www.happy-bears.com/lifestation/
配下のコンテンツを表示させること、
URLを正規化することです。
## Cloufdfront
- www.happy-bears.com ドメインを司っている CloudFront に ↓ の設定を追加
- オリジン
(既存コーポレートサイトをコントロールしてる) ELB
(Amplify コンソールがデプロイした) S3 バケット
- Cache Behavior
www.happy-bears.com/ へのリクエストを ELB へ流す
www.happy-bears.com/lifestation/ へのリクエストを S3 バケットへ流す
- Behavior
/lifestation* = S3
/Defult(*) = ELB
とします。
ここで、
[Default Root Objectsについて](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DefaultRootObject.html)
↑を参照で、How Headers Work With Default Root Objectsの章から、サブディレクトリ
www.happy-bears.com/lifestation/
のサブディレクトリのURIに対してのアクセスのRequest headerにindex.htmlをつけないといけません。
こちら自体は、Cloudfront Functionで[url-rewrite-single-page-apps](https://github.com/aws-samples/amazon-cloudfront-functions/tree/main/url-rewrite-single-page-apps)
によってできます。
### 質問① Cloudfrontのコンテンツ取得とS3のファイル構造が関係しているのか?
実験をした際に
```
S3 バケット
├── index.html
├── 省略
```
では表示できなくて、ディレクトリ↓
```
S3 バケット
└── lifestation
├── index.html
├── 省略
```
とすることで表示をすることができました。
https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-folders.html
を参照すると。
> Amazon S3 has a flat structure instead of a hierarchy like you would see in a file system.
ファイル構造ではなくてフラットみたいなことが書いてあるので、表示されなかった原因にファイル構造は関係がないのかな?と思っていたのですが、
> For example, you can create a folder on the console named photos and store an object named myphoto.jpg in it. The object is then stored with the key name photos/myphoto.jpg, where photos/ is the prefix.
階層を合わせないといけないのかなとも思っている状況です。
### 質問② URL正規化と、Add index.htmlをCloudfront Functionで実装すると、表示が上手くされない
今回のパターンですと、URL正規化とAdd index.htmlをCLoudfront Functionによって実現をしようと思ってます。
[公式ドキュメント](https://github.com/aws-samples/amazon-cloudfront-functions)と[参考](https://michimani.net/post/aws-normalize-url-using-cloudfront-functions/)
を利用して実装をしました。
実装の内容はViewer Request をトリガーに、 / 無しのリクエストを / にリダイレクトしたり、 / でのリクエストに /index..html を補完してオリジンにリクエストを流します。
↓コードです。
```
function handler(event) {
var request = event.request;
var headers = request.headers;
var host = request.headers.host.value;
var uri = request.uri;
var normalization = '/mv-s3/';
var newurl = `https://${host}/mv-s3/`
//originをヘッダーにつける。
if (!headers.origin) {
headers.origin = {value: `https://${host}`};
console.log();
}
// URL正規表現をリダイレクト
if (uri.match(/((test|mv-s3)(\/.*[^\/])?|\/index\.html)$/)) {
var redirectURL = uri.replace('/index.html', '') + '/';
var response = {
statusCode: 301,
statusDescription: 'Found',
headers:
{ "location": { "value": redirectURL }}
}
console.log();
return response;
}
//originに対してはindex.htmlを付与
var actualUri = uri.replace(/\/$/, '\/index.html');
request.uri = actualUri;
return request;
}
```
このように実装をしました。
テストの結果は、
"uri": "/mv-s3",/mv-s3/index.html
```
{
"FunctionSummary": {
"Name": "kurashi-station-request",
"Status": "UNASSOCIATED",
"FunctionConfig": {
"Comment": "",
"Runtime": "cloudfront-js-1.0"
},
"FunctionMetadata": {
"FunctionARN": "arn:aws:cloudfront::697218682574:function/kurashi-station-request",
"Stage": "DEVELOPMENT",
"CreatedTime": "2021-06-10T08:06:19.138Z",
"LastModifiedTime": "2021-06-22T06:48:49.833Z"
}
},
"ComputeUtilization": "39",
"FunctionExecutionLogs": [],
"FunctionErrorMessage": "",
"FunctionOutput": {
"response": {
"headers": {
"location": {
"value": "kurashidemo.happy-bears.com/mv-s3/"
}
},
"statusDescription": "Found",
"cookies": {},
"statusCode": 301
}
}
}
```
そして、
"uri": "/mv-s3/">>正規表現
はindex.htmlを補完して200を返します。
```
{
"FunctionSummary": {
"Name": "kurashi-station-request",
"Status": "UNASSOCIATED",
"FunctionConfig": {
"Comment": "",
"Runtime": "cloudfront-js-1.0"
},
"FunctionMetadata": {
"FunctionARN": "arn:aws:cloudfront::697218682574:function/kurashi-station-request",
"Stage": "DEVELOPMENT",
"CreatedTime": "2021-06-10T08:06:19.138Z",
"LastModifiedTime": "2021-06-22T06:48:49.833Z"
}
},
"ComputeUtilization": "40",
"FunctionExecutionLogs": [],
"FunctionErrorMessage": "",
"FunctionOutput": {
"request": {
"headers": {
"origin": {
"value": "https://kurashidemo.happy-bears.com"
},
"host": {
"value": "kurashidemo.happy-bears.com"
},
"accept": {
"multiValue": [
{
"value": "text/html"
},
{
"value": "application/xhtml+xml"
}
],
"value": "text/html"
}
},
"method": "GET",
"querystring": {},
"uri": "/mv-s3/index.html",
"cookies": {}
}
}
}
```
こちらを実際に該当のorigin Behiverにアタッチすると、
↓のようになります。
domain/mv-s3/

HARファイルを参照すると、
```
$ cat check.txt | jq -r .log.entries[].request.url
https://kurashidemo.happy-bears.com/mv-s3/
https://kurashidemo.happy-bears.com/mv-s3/styles.3ff695c00d717f2d2a11.css
https://kurashidemo.happy-bears.com/mv-s3/runtime.acf0dec4155e77772545.js
https://kurashidemo.happy-bears.com/mv-s3/polyfills.35a5ca1855eb057f016a.js
https://kurashidemo.happy-bears.com/mv-s3/main.79618c688ddc5292474a.js
https://kurashidemo.happy-bears.com/mv-s3/kurashidemo.happy-bears.com/mv-s3/styles.3ff695c00d717f2d2a11.css/
https://kurashidemo.happy-bears.com/mv-s3/kurashidemo.happy-bears.com/mv-s3/runtime.acf0dec4155e77772545.js/
https://kurashidemo.happy-bears.com/mv-s3/kurashidemo.happy-bears.com/mv-s3/polyfills.35a5ca1855eb057f016a.js/
https://kurashidemo.happy-bears.com/mv-s3/kurashidemo.happy-bears.com/mv-s3/main.79618c688ddc5292474a.js/
```
domain/mv-s3 or domain/mv-s3/index.htmlに関してのアクセス。↓

も同じく、ファイルが複数回読まれてます、、
```
cat check2.txt | jq -r .log.entries[].request.url
https://kurashidemo.happy-bears.com/mv-s3
https://kurashidemo.happy-bears.com/mv-s3/
https://kurashidemo.happy-bears.com/mv-s3/styles.3ff695c00d717f2d2a11.css
https://kurashidemo.happy-bears.com/mv-s3/runtime.acf0dec4155e77772545.js
https://kurashidemo.happy-bears.com/mv-s3/polyfills.35a5ca1855eb057f016a.js
https://kurashidemo.happy-bears.com/mv-s3/main.79618c688ddc5292474a.js
https://kurashidemo.happy-bears.com/mv-s3/styles.3ff695c00d717f2d2a11.css/
https://kurashidemo.happy-bears.com/mv-s3/runtime.acf0dec4155e77772545.js/
https://kurashidemo.happy-bears.com/mv-s3/polyfills.35a5ca1855eb057f016a.js/
https://kurashidemo.happy-bears.com/mv-s3/main.79618c688ddc5292474a.js/
```
それぞれのURIに対してCURLコマンドを実行します。
```
curl -I https://kurashidemo.happy-bears.com/mv-s3/
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 583
Connection: keep-alive
Date: Wed, 23 Jun 2021 04:05:19 GMT
Last-Modified: Tue, 22 Jun 2021 12:09:13 GMT
Etag: "c1c299735d477691afa66c41010e25be"
X-Amz-Version-Id: M9NmYNZisvxrMA5ngNfJmY7xecPAetfn
Accept-Ranges: bytes
Server: AmazonS3
Via: 1.1 0b0fd1e326ceb88593e799c95732c627.cloudfront.net (CloudFront)
Access-Control-Allow-Origin: *
X-Cache: Miss from cloudfront
X-Amz-Cf-Pop: NRT12-C2
X-Amz-Cf-Id: 9t9OJ6HmhoV5w3VQftfUNfUXRJUYLVbK0pTExfJM9MypYHMbDc-1xg==
curl -I https://kurashidemo.happy-bears.com/mv-s3
HTTP/1.1 301 Found
Server: CloudFront
Date: Wed, 23 Jun 2021 04:04:11 GMT
Content-Length: 0
Connection: keep-alive
Location: /mv-s3/
X-Cache: FunctionGeneratedResponse from cloudfront
Via: 1.1 b4fb3cede6d11b735dc8f5d78841f471.cloudfront.net (CloudFront)
X-Amz-Cf-Pop: NRT12-C2
X-Amz-Cf-Id: 8Uipxydv3taHDzu199YVEgfAOX6Vul0dau0mtbOf0K32xrGgpKG0Ug==
```
こちらはテストのとうりに成功をしているように思うのですが、
ブラウザで参照をした場合に失敗する。(ファイルが複数回読まれてしまっている。)
以上が状況であり、
シンプルなadd index.hmtl関数をアタッチすると表示されるので、上記記載のコードに問題があると思ってます。
行っていることとしては、末尾にindex.htmlを付与してオリジンにリクエストをかけるなので、同じだと思ってます。
何が原因かも分からない状況なので、ご教授お願いしたいです。
# 2021/6/25 更新AWS返信を受けて
>/mv-s3/にアクセスをした際の、HARファイルを確認すると、
>
>Check.txtにHARファイルのコピーがあります。
>こちらを見ると、
...(中略)...
>正式なオブジェクト:mv-s3/index.htmlへアクセスできていません。
>さらにこちらのruntime.acf0dec4155e77772545.jsなどのファイルがリダイレクトされています。
>
>こちらの原因解消にはどのようなトラブルシュートが当てはまるかを教えていただければ幸いです。
>Testではmv-s3/index.htmlのアクセスができているので実際のブラウザで挙動が違っているように思えます。
パス mv-s3/ へのリクエストに対し、CloudFront Functions のコーディングにより、mv-s3/index.html へリダイレクトするようレスポンスされているといった状況でお間違いないでしょうか。
ご共有頂いた添付ファイルより、URL https://kurashidemo.happy-bears.com/mv-s3/ へのリクエストを確認したところ、ステータスコード 200、また Location ヘッダーのないレスポンスのみと見受けられ、リダイレクトは発生しないレスポンスであると考えられました。
お手数ですが、CloudFront Functions のコードのリダイレクトのレスポンスを行うロジックについてご確認をお願い致します。
>サブディレクトリのオブジェクトリソースにはindex.htmlの付与をしてリクエストするかと思うのですが、
>S3のファイル構造とURIを合わせる必要があるのかないのかの判断がつかなくて困ってます。
>
>つまり、
>URI ::kurashidemo.happy-bears.com/mv-s3/の場合には、S3のファイル構造を以下にしないといけないという認識であってますでしょうか?
>S3--mv-s3
> |
> |---index.html
> |---runtime.acf0dec4155e77772545.js
> |---main.79618c688ddc5292474a.js
記載頂いた例のように、kurashidemo.happy-bears.com/mv-s3/ により CloudFront へリクエストを行う場合、S3 オリジン側は上記 uri の変更に伴う mv-s3/index.html といったキーのオブジェクトを応答する必要があるものと存じます。(※オリジンのパスを別に設定していないと仮定した場合
その他の例に挙げて頂いたキーのオブジェクトにつきましては、特にサンプルコードの内容が影響を与えるものではございませんので、クライアントによるリクエスト次第でございます。
# 何が知りたいのか? どんなことを期待しているのか?
1. 現状のCloudfront Functionをアタッチした際に起きている挙動はどう説明できるか?また、トラブルシュートの方法。
2. CloudfrontからS3のコンテンツ取得ができる条件はなんなのか?
3. Amplifyで自動で生成されるCloudfrotなどそれぞれ独立して生成されるCloudforntを1つに集約させるときに注意することは何か?