LoginSignup
3
3

More than 3 years have passed since last update.

SPA(S3+Cloud Front)でLambda@Edgeを使ってTwitterカードを表示する〜コンソールOnly

Last updated at Posted at 2020-03-29

Twitterカードに代表されるOGPの実装は、基本的にmetaタグに情報を加えるだけ。
ただ、React等SPAとして実装されたサイトでOGPを実装する場合は一工夫必要。

OGPの基本的な仕組み

  1. ユーザーがSNS(Twitterなど)にリンクを貼る
  2. 各SNSのボットがそのURLにアクセスして、metaタグを読みにいく

この時、ボットがJSを実行できないために、
SPAの場合は常にルートのindex.htmlのmetaタグが読み込まれてしまう
=表示される画像などを動的に変更することができない

指針

  1. CloudFrontのビューワーリクエストにLambda@Edgeを差し込む
  2. UserAgentを判定し、botからのアクセスの時だけ、動的にmetaタグを追加したHTMLをレスポンスとして返す

ユーザーがSNSにリンクを貼ってボットがサイトに来たときだけ、表示させたい画像をmetaタグに詰めて渡してあげる

実装

Lambda@Edgeの実装

Lambda@Edgeはus-east1(バージニア北部)リージョンでしか使用できないため、
それ以外のリージョンにいる場合は切り替えてから関数を作成する。

コードは https://qiita.com/kurimoto/items/6212372ead6522161a60 を参考にした。
ユーザーからのリクエストを読み取って、UserAgentを判定し、Twitterbot等の場合だけ作成したレスポンスを返す。

index.js
'use strict';

const bots = ['Twitterbot'];

exports.handler = (event, context, callback) => {
  const request = event.Records[0].cf.request;
  const userAgent = request.headers['user-agent'][0].value;
  const isBot = bots.some(v => {
    return userAgent.includes(v);
  });
  if (isBot) {
    const body = getContent()
    const response = {
      status: '200',
      statusDescription: 'OK',
      headers: {
        'content-type': [{
          key: 'Content-Type',
          value: 'text/html'
        }]
      },
      body: body
    };
    callback(null, response);
  } else {
    callback(null, request);
  }
};

const getContent = () => { 
 return = `
  <!doctype html>
  <html lang="ja">
  <head>
  <meta charset="utf-8" />
  <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
  <meta content="width=device-width, initial-scale=1.0" name="viewport" />
  <meta content="R-bies,INC." name="author" />
  <title>タイトル</title>
  <meta name="twitter:card" content="summary" />
  <meta property="og:url" content="http://example.com/" />
  <meta property="og:title" content="Example" />
  <meta property="og:image" content="${imageUrl}" />
  </head>
  <body>
  </body>
  </html>
  `;
};

上のコードはそのまま動かない。(metaタグに設定しているimageUrlが定義されていないから)

UserAgentを判定する
あらかじめ指定したボットだった場合は動的にタグを追加してレスポンスとして返す。
それ以外はリクエストをそのまま実行する(S3にアクセスする)

というものになっている。
ので、動的に画像を差し替えたりしたいときは、条件を追加したり、URLに応じてDBからfetchしてきたりして、imageUrlを定義してあげればよい。

参考

CloudFront経由のイベントは下記のフォーマットで渡ってくるので、
テストをする際は下記をコピペしてあげたり、イイ感じに改変すればよい

{
  "Records": [
    {
      "cf": {
        "config": {
          "distributionDomainName": "d111111abcdef8.cloudfront.net",
          "distributionId": "EDFDVBD6EXAMPLE",
          "eventType": "viewer-request",
          "requestId": "4TyzHTaYWb1GX1qTfsHhEqV6HUDd_BzoBZnwfnvQc_1oF26ClkoUSEQ=="
        },
        "request": {
          "clientIp": "203.0.113.178",
          "headers": {
            "host": [
              {
                "key": "Host",
                "value": "d111111abcdef8.cloudfront.net"
              }
            ],
            "user-agent": [
              {
                "key": "User-Agent",
                "value": "Twitterbot"
              }
            ],
            "accept": [
              {
                "key": "accept",
                "value": "*/*"
              }
            ]
          },
          "method": "GET",
          "querystring": "",
          "uri": "/example/5674591867371520"
        }
      }
    }
  ]
}

Lambda@Edgeへのデプロイ

関数を作成してテストも通ったら、Lambda@Edgeへデプロイする。

関数設定のトリガーを追加するところから、CloudFrontを選択
スクリーンショット 2020-03-29 22.56.38.png

デプロイするディストリビューションを設定
イベントをビューアーリクエストに設定
スクリーンショット 2020-03-29 22.58.11.png

追加する

Lambdaの実行ロールの設定

開く
スクリーンショット 2020-03-29 23.01.24.png

信頼関係を編集する
スクリーンショット 2020-03-29 23.02.17.png

下記を貼る

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "edgelambda.amazonaws.com",
          "lambda.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

CloudFrontの設定

コレをしないと延々503が出て困る

デプロイしたディストリビューションのbehaviorを追加する
スクリーンショット 2020-03-29 23.03.46.png

Lambdaを実行するパスのパターンを設定する。全てで動かす場合は *
スクリーンショット 2020-03-29 23.04.24.png

実行させるLambdを設定する
スクリーンショット 2020-03-29 23.05.55.png
ARNはLambda画面の右上にある
スクリーンショット 2020-03-29 23.07.50.png

これで追加すると、CloudFrontにデプロイされ、
晴れてOGPタグを動的に差し替えることに成功する

3
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3