3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【LIFF】「店舗コードが指定されていません」と出る → クエリパラメータが消える問題と解決法

3
Posted at

はじめに

LIFFで店舗コードを ?code=XXX で渡そうとしたら、リダイレクト後に値が消えてエラーになりました。
原因は liff.init() を呼ぶ前にクエリを取りにいっていた こと。

ざっくりイメージ(空港の手荷物に例える)

LIFFの認証は 空港の保安検査 みたいなもの。
クエリパラメータ(?code=ヒスイ)はスーツケースで、そのままじゃ通れないので 箱に預けさせられる

預ける前: ?code=ヒスイ              ← スーツケース丸見え
預けた後: ?liff.state=?code=ヒスイ   ← 箱(liff.state)の中に押し込まれた

liff.init()到着空港での荷物受け取り。これを呼ぶとSDKが箱を開けて、元のスーツケースを返してくれる。

バグの正体: 荷物を受け取る前(liff.init() の前)に「ヒスイのスーツケースくれ」と言ったから、まだ箱の中で null が返ってきた。

結論

クエリパラメータの取得は 必ず liff.init() の後 で行う。

// ❌ NG
const code = searchParams.get("code");  // liff.init() より前
useEffect(() => {
  liff.init(...);
}, []);

// ✅ OK
useEffect(() => {
  await liff.init(...);
  const params = new URLSearchParams(window.location.search);
  const code = params.get("code");
}, []);

起きたこと

QRコードに以下のURLを埋めた:

https://liff.line.me/{LIFF_ID}?code=ヒスイ

iPhoneで読み取ると、LIFFが認証してアプリページにリダイレクトする。
そこで searchParams.get("code") を呼ぶと null が返ってくる。
画面には「店舗コードが指定されていません」のエラー。

原因

LIFFは認証時に元のクエリパラメータを liff.state というキーに詰め替えてリダイレクトする:

リダイレクト前
https://liff.line.me/XXX?code=ヒスイ

リダイレクト後(liff.init() 前のURL)
https://my-app.vercel.app/liff/select?liff.state=?code=ヒスイ
                                       ↑
                            「ヒスイ」が中に押し込められてる

この状態で searchParams.get("code") しても、クエリ直下に code は存在しないので null

そして liff.init() を呼ぶとSDKが liff.state を解凍してURLを復元してくれる

liff.init() 後のURL
https://my-app.vercel.app/liff/select?code=ヒスイ
                                      ↑ 復元される

つまり「クエリを取るタイミングが早すぎた」のが原因。

解決手順

useEffect 内で liff.init() を待ってから クエリを読む

useEffect(() => {
  const init = async () => {
    await liff.init({ liffId: process.env.NEXT_PUBLIC_LIFF_ID! });

    if (!liff.isLoggedIn()) {
      liff.login({ redirectUri: window.location.href });
      return;
    }

    // liff.init() の後で取得
    const params = new URLSearchParams(window.location.search);
    const code = params.get("code");
    // ...
  };
  init();
}, []);

Next.js の useSearchParams フックはマウント時のURLを参照するので、LIFFの書き換え後の値が取れない。window.location.search を直接読む のが確実。

なぜそうなる仕組みなのか

LIFFは認証フローのために LINEのサーバーを経由する。その時に元のURLパラメータをそのまま渡せないので、liff.state という箱に詰めて持ち運んでいる。

これはLIFF v2 の仕様で、SDKが解凍してくれるから普段は意識しないが、SDK初期化前にクエリを読もうとすると詰む

学び

  • LIFF を使うページでは、liff.init() の後にクエリ取得する
  • useSearchParams ではなく window.location.search を使う
  • 「リダイレクト後にパラメータが消えた」と感じたら liff.state を疑う
3
2
0

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
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?