【LINE Messaging API】URLプレビューの表示について

Messaging APIをご利用の皆様こんにちは。

今回はMessaging APIでURLをユーザーに送信した場合の、
URLプレビューについて調べてみました。

↓こういうやつです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620553/4745859c-1e9d-5bef-a046-1b4ccdc580db.png)



# 表示内容の制御方法

以下のFAQにもあるとおり、LINEのURLプレビューはOGPの規格に準拠するようです。
https://developers.line.biz/ja/faq/#how-are-the-url-previews-generated

対応しているパラメータは

```
og:title	
og:description	
og:image
```

のみようです。
こんな感じでOGPの制御ができるようです。

```html
<!DOCTYPE html>
<html lang="ja">
  <meta property="og:title" content="title:URLプレビューテスト"> 
  <meta property="og:description" content="description:URLプレビューテスト">
  <meta property="og:image" content="https://placehold.jp/d92733/ffffff/150x150.png?text=LINE%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E3%83%86%E3%82%B9%E3%83%88">
<head>
  <meta charset="utf-8">
</head>
<body>
</body>
</html>
```

# OGPのキャッシュ

LINEアプリで表示したURLプレビューについては、キャッシュが作成されるようです。
**一度キャッシュが作成された場合、しばらく経過しないと新しいOGPタグが反映されないようです。**

キャッシュにはLINEアプリ側と、LINEサーバー側の2種類があるようで、
片方でもキャッシュが残ってる場合、一定期間OGPタグ情報の再取得を行わないようです。

ただし、以下の方法でキャッシュを削除することで、新しいOGPタグを即時に反映させることができる
場合があるようです。（双方実施する必要があります。）

### LINEアプリ本体のキャッシュを削除する

iOSの場合:
LINEアプリの設定 > トーク > データの削除 > キャッシュデータ
Androidの場合:
OSのアプリ > LINE >ストレージとキャッシュ > キャッシュを削除

### LINEサーバー側のキャッシュを削除する
これは不可能かと思いきや、いつの間にか以下のような公式ツールが公開されていました。
https://poker.line.naver.jp/

このサイトはプレビューも確認できるので便利だとおもいます。
上記FAQページにリンクがありました。

利用方法は見たまんま、URLを指定してClear Cacheするだけです。
<img width="600"src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620553/3e8418cb-0512-45e7-3e0c-191645bc56e5.png">

Clear Cacheした後、LINEのクローラーがOGPの再取得にアクセスしてきました。

```
[27/May/2021:14:44:20 +0000] "GET /login-url-preview-test2 HTTP/1.1" 302 801 "-" "facebookexternalhit/1.1;line-poker/1.0"
```


# 応用編
LINEのOGPを取得するクローラーのユーザーエージェントは
**"facebookexternalhit/1.1;line-poker/1.0"** です。

このUAからのアクセスの場合にユーザーがアクセスするページのHTMLとは別の
HTMLをレスポンスすることで、プレビュー内容をカスタマイズできます。

例えば、以下のURLではLINEログインの認可リクエストへのリダイレクトを行っています。
https://myucy.herokuapp.com/login-url-preview-test2
この場合のURLプレビューは、以下のようにLINEのログインページのものが表示されるので
UX的にはあまり良くないです。
<img width="３００"src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620553/2baca4cb-c9b7-7400-dbe8-e201fbb8fe56.png">

以下のURLでは上記と同じくLINEログインの認可リクエストへのリダイレクトを行っていますが、
LINEクローラーからのアクセス時のみ、処理を変更しています。
すると、以下のように表示をカスタマイズできます。
こうすることでユーザーに不信感を与えにくいUXを実現できます。

https://myucy.herokuapp.com/login-url-preview-test
<img width="３００"src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620553/840e2399-686a-175a-2ac5-a61c1f33abe5.png">

Flaskを使った処理の例です。

```python
from argparse import ArgumentParser
from flask import Flask, request, abort, render_template, jsonify, redirect, session, make_response
import secrets
import base64
import hashlib
import urllib.request

app = Flask(__name__,static_folder='static')

@app.route('/login-url-preview-test', methods=['GET'])
def LoginUrlPreview():

    #LINEクローラーのみ処理を変更
    if request.headers.get('User-Agent') == "facebookexternalhit/1.1;line-poker/1.0":
        return render_template('login-url-preview-test.html')
    code_verifier = secrets.token_urlsafe(48)
    code_challenge = base64.urlsafe_b64encode(hashlib.sha256(code_verifier.encode('utf-8')).digest()).decode('utf-8').strip('=')
    
    queries = {}
    queries['response_type'] = "code"
    queries['client_id'] = "1654102793"
    queries['redirect_uri'] = "https://example.com"
    queries['scope'] = "profile"
    queries['state'] = secrets.token_urlsafe(32)
    queries['code_challenge_method'] = "S256"
    queries['code_challenge'] = code_challenge

    authorize_url = 'https://access.line.me/oauth2/v2.1/authorize?' + \
        urllib.parse.urlencode(queries)

    return redirect(authorize_url)

```

login-url-preview-test.html

```ｈｔｍｌ
<!DOCTYPE html>
<html lang="ja">
  <meta property="og:title" content="title:URLプレビューテスト"> 
  <meta property="og:description" content="description:URLプレビューテスト">
  <meta property="og:image" content="https://placehold.jp/d92733/ffffff/150x150.png?text=LINE%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E3%83%86%E3%82%B9%E3%83%88">
<head>
  <meta charset="utf-8">
</head>
<body>
</body>
</html>
```