にせねこメモ

はてなダイアリーがUTF-8じゃないので移ってきました。

静的なHTMLページをoEmbedで他サイトに埋め込み可能にする

YouTubeなどの動画サイトの動画や、ブログ記事の内容をブログカードとして埋め込むための規格の一つとして、oEmbedがある。はてなブログもoEmbedに対応している(埋め込む側・埋め込まれる側両方とも)。

仕様概要

oEmbedの仕様は https://oembed.com/ にある。

これを見ると、埋め込まれる側がoEmbedに対応するには、だいたい次のようになっている。

URL schemeはendpointと同じドメイン(サブドメインは違ってもよい)で、http/httpsも一致してる必要がある。

http://flickr.com/services/oembed?url=http%3A//flickr.com/photos/bees/2362225867/

のようにAPI endpointにURL schemeを渡すと、仕様に定義されているようなパラメータをもったJSONまたはXMLが返ってくる。JSONXMLのどちらを返すかは、クエリパラメータで指定することもできるし、別々のendpointを用意することもできる。

さて、これではURL schemeAPI endpointのペアを知らないとoEmbedを呼び出すことはできない。ここで、HTMLページにその情報を埋め込むことで発見できるようにしている。次の例が挙げられている。

<link rel="alternate" type="application/json+oembed"
  href="http://flickr.com/services/oembed?url=http%3A%2F%2Fflickr.com%2Fphotos%2Fbees%2F2362225867%2F&format=json"
  title="Bacon Lollys oEmbed Profile" />
<link rel="alternate" type="text/xml+oembed"
  href="http://flickr.com/services/oembed?url=http%3A%2F%2Fflickr.com%2Fphotos%2Fbees%2F2362225867%2F&format=xml"
  title="Bacon Lollys oEmbed Profile" />

静的Webページにも対応できるか

API endpointは入力されたURLに対応して動的に出力を返すことを前提としている。
しかし、適当にHTMLで書いたページを公開するのに動的なCGIを置くのも気が引けるので、ページ毎にendpointを用意したら、動的な仕組みを用意せずともoEmbed対応できるのでは? と考えて、やってみた。

以下の4ファイルは https://nixeneko.sakura.ne.jp/hatenablog/20180316_oembed/ 以下にアップロードすることを前提としている。

index.html

<!DOCTYPE html>
<html>
<head>
<title>oEmbedのテスト</title>
<link rel="alternate" type="application/json+oembed"
  href="https://nixeneko.sakura.ne.jp/hatenablog/20180316_oembed/oembed.json"
  title="oEmbed Profile of oEmbedのテスト"/>
<link rel="alternate" type="text/xml+oembed"
  href="https://nixeneko.sakura.ne.jp/hatenablog/20180316_oembed/oembed.xml"
  title="oEmbed Profile of oEmbedのテスト"/>
</head>
<body>
このページを埋め込み可能にします。
</body>
</html>

クエリパラメータのurlは固定なので省いた。Vineなんかも似た様な感じで、動画毎にJSON/XMLファイルのURLを用意してクエリ文字列を使わずに対処してるっぽい。
参考: はてなブログの貼り付けにVineが対応していた - すなばいじり

oembed.json

{
    "author_name": "nixeneko",
    "html": "<div style=\"width:100%;height:120px;border:1px solid;font-weight:bold;overflow:hidden;background-color:white;\"><img src=\"https://nixeneko.sakura.ne.jp/hatenablog/20180316_oembed/simarin.jpg\" width=120 height=120 style=\"float:left;margin-right:10px;\"/>ここをキャンプ地とする</div>",
    "url": "https://nixeneko.sakura.ne.jp/hatenablog/20180316_oembed/index.html",
    "version": "1.0",
    "height": 120,
    "width": "100%",
    "description": "おい概要食わねぇか",
    "type": "rich",
    "title": "埋め込みどうでしょう"
}

JSONXMLの情報は、oEmbed公式の説明やはてなブログの設定などを参考に書いた。ブログなどではhtmlパラメータが埋め込まれて表示されるっぽい。
また、widthに100%と指定しているがこれは仕様としては正しくなく、ピクセル単位の数値にすべきであるが、はてなブログのoEmbed情報では100%となっている。

oembed.xml

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<oembed>
  <author_name>nixeneko</author_name>
  <description>おい概要食わねぇか</description>
  <height>120</height>
  <html>&lt;div style=&quot;width:100%;height:120px;border:1px solid;font-weight:bold;overflow:hidden;background-color:white;&quot;&gt;&lt;img src=&quot;https://nixeneko.sakura.ne.jp/hatenablog/20180316_oembed/simarin.jpg&quot; width=120 height=120 style=&quot;float:left;margin-right:10px;&quot;/&gt;ここをキャンプ地とする&lt;/div&gt;</html>
  <title>埋め込みどうでしょう</title>
  <type>rich</type>
  <url>https://nixeneko.sakura.ne.jp/hatenablog/20180316_oembed/index.html</url>
  <version>1.0</version>
  <width>100%</width>
</oembed>

.htaccess

AddType application/json .json
AddType text/xml .xml

HTTPレスポンスヘッダのContent-Typeを適切に設定する必要があり、JSONはapplication/jsonXMLtext/xmlにする。

テスト

はてなブログではURL記法で:embedを指定することで、oEmbed対応サイトを記事に埋め込むことができる。

[https://nixeneko.sakura.ne.jp/hatenablog/20180316_oembed/index.html:embed]

と書くと、↓のようにoEmbedの埋め込みが表示される。

ここをキャンプ地とする
↑ここまで

いけた! htmlパラメータがそのまま埋め込まれているようである。

また、 http://iframely.com/debug などを使ってoEmbedが認識されているかを確かめてみることもできる。

備考

ブログなどでoEmbedを埋め込む側ではセキュリティ的にホワイトリスト方式をとっているものもあり、そこではこのような得体のしれないoEmbedは参照されないことになるかもしれない。

JSONを手で書くのは現実的ではないので、何らかの方法で自動生成した方がよさそう。

oEmbedの情報はキャッシュされるので、JSON/XMLに変更を加えても反映にしばらく時間がかかる可能性がある。テスト中はキャッシュの生存期間cache_age (秒数を指定)を小さく指定しておくといいかもしれないが、必ずしもcache_ageの値を使うとは限らないらしい。

(2018-03-22 追記)
今回は埋め込み用HTMLにiframeを使っていないが、oEmbedで埋め込めるようになっているページは、大抵はiframeを使って別のHTMLページを読み込ませるようになっている。このとき、iframeによって埋め込まれるページのレスポンスヘッダのContent-Security-Policyが他サイトへの埋め込みを許可するように適切に設定されていないと、読み込まれないことになる。