以下の記事を参考に、FlutterでOGP情報の表示ビューを作成しました。
しかし、x.comのポストのリンクについてはOGPの取得に失敗し、正常に表示できませんでした。これを表示できるようにするまでの流れを共有します。
OGP取得を成功させるために必要なポイントは2つありました。
- リクエストヘッダに"User-Agent: bot"をつける
- リダイレクトの処理にもヘッダーをつける
プログラム
最終的にうまく行ったプログラムは以下です。
metadata_fetchというライブラリを使っているので、
flutter pub add metadata_fetch
で追加してください。
import 'package:metadata_fetch/metadata_fetch.dart';
import 'package:http/http.dart' as http;
Future<http.StreamedResponse> httpGetWithoutAutoRedirect(Uri uri) async {
http.Request req = http.Request("Get", uri);
req.followRedirects = false;
req.headers["User-Agent"] = "bot";
http.Client baseClient = http.Client();
return await baseClient.send(req);
}
Future<Metadata> fetchMetaData(String url) async {
var streamedResponse = await httpGetWithoutAutoRedirect(Uri.parse(url));
//無限リダイレクトの回避のため最大5回までのループにしています
for (var i = 0; streamedResponse.isRedirect && i < 5; i++) {
final redirectURL = streamedResponse.headers["location"];
if (redirectURL == null) {
safePrint('fetching redirect url failed $url');
break;
}
streamedResponse =
await httpGetWithoutAutoRedirect(Uri.parse(redirectURL));
}
final response = await http.Response.fromStream(streamedResponse);
final document = MetadataFetch.responseToDocument(response);
return MetadataParser.parse(document, url: url);
}
}
注意点
リクエストヘッダに"User-Agent: bot"をつける
twitter.comに普通にアクセスすると、ヘッダーにOGPのmetaデータが付いてこないようです。リクエスト時にヘッダーに"User-Agent: bot"をつけると付いてくるようになります。
↓こちらを参考にさせていただきました。
リダイレクトの処理にもヘッダーをつける
現在、Xの共有URLはx.comですが、これはtwitter.comへのリダイレクトURLになっています。Dartで普通にhttpリクエストを送るときは、
http.get(Uri.parse('https://example.com'), headers:{"User-Agent" : "bot"});
のようにな書き方になります。
この関数は与えられたURLがリダイレクトURLであれば、自動的にリダイレクト先まで辿ってレスポンスを返してくれます。しかし、どうやら辿る際に指定したヘッダーは無視されてしまうようです。これでは、Twitterのよううなmetaデータの取得に"User-Agent: bot"のヘッダーを要するサイトに対応できません。
そこで、リダイレクト時にもちゃんとヘッダーを送信し直してくれるような関数を自作する必要があります。
以下の部分がその関数です。
Future<http.StreamedResponse> httpGetWithoutAutoRedirect(Uri uri) async {
http.Request req = http.Request("Get", uri);
req.followRedirects = false;
req.headers["User-Agent"] = "bot";
http.Client baseClient = http.Client();
return await baseClient.send(req);
}
参考にした記事はこちら↓