※この記事は2023/06/04に投稿されたZennのブログ。
https://zenn.dev/uyas/articles/0b7dcbb46d8031
の転載になります!!!自分の記事の無断転載!
無断・・・?
無断じゃないか。
以下Zennの記事の内容です。
初めに
Zennで記事を書いていると、外サイトのurlを入力するといい感じにOGPが表示されます。
https://u-yas.dev
↑こんな感じです。ちなみにこれは僕の個人ブログです。よかったら来てください!
そういえば、自分のサイトにOGPを設定する記事とかはよくあるけど他サイトのOGPを表示する方法とかあんまり見ないな・・・と思うようになりました。
ていうか自分のブログだとできてないじゃん・・・
よし!実装しよう!
超簡単だと思ったら・・・
(o'ω'o) < OGPデータを手に入れるにはとりあえずhrefに設定しているサイトのhtml取ってくる -> htmlのパースをする -> metaタグのogpに関する情報を取ってくればええってことやろ。それならapi作らなくてもクライアントからfetchでデータ取得してくればええやないか!簡単簡単♫
(o'ω'o) < CORSのこと完全に忘れてた・・・そりゃそうだ・・・
(o'ω'o) < じゃあ、APIからfetch->htmlをパース->フロントエンドにogpデータを返さないと・・・
(o'ω'o) < API作らんと・・・
(o'ω'o) < 自分のブログはCloudflare PagesでできてるからCloudflare Workersでささっと実装したいな・・・
(o'ω'o) < でもfreeプランのCloudflare Workersって cpu runtime limitsが10ms しかないからな・・・
(o'ω'o) < htmlのパースとか実行したら10msじゃ絶対できないだろ・・・
(o'ω'o) < はぁ・・・
と半ばあきらめかけていました・・・このドキュメントを見るまでは・・・
https://developers.cloudflare.com/workers/runtime-apis/html-rewriter/
https://blog.cloudflare.com/introducing-htmlrewriter/
(o'ω'o) !!!!
(o'ω'o) < なんか・・・
( o'ω'o ) < いけそう!!!!
HTMLRewriterとは?
The HTMLRewriter class allows developers to build comprehensive and expressive HTML parsers inside of a Cloudflare Workers application. It can be thought of as a jQuery-like experience directly inside of your Workers application. Leaning on a powerful JavaScript API to parse and transform HTML, HTMLRewriter allows developers to build deeply functional applications.
要はCloudflare Workers用に作られたHTMLパーサーらしいです!まさに僕がいま一番欲しかったものです!!!
超簡単に実装できた・・・!!!!!
Cloudflare Workersに以下のようなコードをちょびっと書くだけでOGPデータを取得し、フロントエンド側に返すことができました!(フレームワークにはHonoを使っています)
// ~~ 他の色々なコード
class OGPParser {
ogpTitle: string;
ogpDescription: string;
ogpImageUrl: string;
ogpSiteName: string;
constructor() {
this.ogpTitle = "";
this.ogpDescription = "";
this.ogpImageUrl = "";
this.ogpSiteName = "";
}
element(element: Element) {
switch (element.getAttribute("property")) {
case "og:title":
this.ogpTitle = element.getAttribute("content") ?? "";
break;
case "og:description":
this.ogpDescription = element.getAttribute("content") ?? "";
break;
case "og:image":
this.ogpImageUrl = element.getAttribute("content") ?? "";
break;
case "og:site_name":
this.ogpSiteName = element.getAttribute("content") ?? "";
break;
default:
break;
}
}
}
// 3秒で考えたpath
app.get("/another-site/ogp", async (c) => {
// ステータスコードとかは適当です。仕事ではちゃんと考えています(涙)
const href = c.req.query("href");
if (href === undefined) {
return c.body("Bad Request", 400);
}
const decodedHref = decodeURIComponent(href);
const siteRes = await fetch(decodedHref);
if (!siteRes.ok) {
return c.body("Not Found", 404);
}
const ogp = new OGPParser();
new HTMLRewriter().on("meta", ogp).transform(siteRes);
// CloudflareのCDN Cacheに乗せればWorkersのリクエスト数を抑えることができるのでCacheを設定する
c.header("Cache-Control", `public, s-maxage=${1 * days}`);
return c.json(ogp);
});
ちゃんと動いています。まさかライブラリを使わずCloudflare WorkersのAPIだけでできるとは思っても見ませんでした・・・
そして、フロントエンド側でごにょごにょします
(^⌒⌒^)
| i i i i i| JSON色付中
| i i i i i|
(;`・ω・)っ-O・゚・⌒)
/ つ━ゝ,. ゚ __.、ノ))
l从从从从l
| ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄|
結果がこちら
まとめ
まさかここまで簡単に、Cloudflare Workersだけで他サイトをfetchしてHTMLをparseする処理が書けるとは思いも見ませんでした・・・ しかもこれ、10msのcpu limitsの制限時間以内に処理が終了しているんです。早すぎる!!!一生ついていきます!!
そんな他サイトのOGPを表示する機能が実装された僕のブログはこちらになります!
たまにネタ記事やZennに乗せるほどでもない雑メモなんかを置いたりしています。是非見に来てください!