Skip to content

網路與登入身分 ​

宣告網域 ​

小程序只能連 miniapp.config.ts 的 domains 裡列出的網域:

ts
domains: ['https://api.example.com', 'https://img.example.com:8443'],
  • 只接受 https:// 加主機名稱,可以帶埠;不能有路徑、查詢字串或結尾的 /。
  • 主機名稱至少兩段(api.example.com),只能有小寫英數與連字號,最後一段不能是純數字。不接受 IP、localhost、底線、萬用字元(*.example.com)。
  • 埠也要完全相同:https://api.example.com 不包含 https://api.example.com:8443。
  • 不在清單內的網址一律擋下,回 DOMAIN_BLOCKED 並上報。

這份清單同時用在:

用途說明
sdk.http.fetch只能請求清單內的網域
圖片、影音(<img>、<video>、CSS 背景圖)可以直接載入清單內網域的檔案
瀏覽器的 fetch/XMLHttpRequestCSP 只放行清單內的網域,但會受 CORS 限制,請改用 sdk.http.fetch

送出請求:sdk.http.fetch ​

ts
import { MiniAppError, sdk } from '@im/miniapp-sdk';

try {
  const res = await sdk.http.fetch('https://api.example.com/v1/orders', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
    body: JSON.stringify({ productId: 'p1' }),
    timeoutMs: 10_000,
  });
  if (res.status !== 200) {
    // 非 2xx 不會 reject,自己判斷 status
  }
  const order = res.json<{ id: string }>();
} catch (e) {
  if (e instanceof MiniAppError) {
    // DOMAIN_BLOCKED、INVALID_PARAMS、TIMEOUT、NETWORK…
  }
}

請求由容器代送,所以:

  • 沒有 CORS 限制,也不帶任何 cookie 或 App 的憑證。
  • 不會自動跟隨轉址:3xx 會原樣回傳,自己讀 location 標頭決定要不要再請求(新網址同樣要在白名單內)。
  • 回應的標頭名稱一律小寫;set-cookie 會被拿掉;同名標頭以 , 合併。
  • body 一律是文字(UTF-8 解碼)。目前不支援二進位內容(上傳檔案、下載圖片)。
  • 回應超過 5 MB 會以 NETWORK 失敗。
  • 建立連線最多 10 秒,超過以 NETWORK 失敗(和 timeoutMs 無關)。

參數規則(違反時回 INVALID_PARAMS):

參數規則
methodGET、POST、PUT、PATCH、DELETE、HEAD(大小寫不拘),預設 GET
headers最多 50 個;名稱只能是 token 字元(英數與 !#$%&'*+.^_`|~-),值只能是可見 ASCII 與 tab(不能有中文或換行,需要時先編碼)
body文字,最多 1 MB(整則呼叫訊息上限也是 1 MB,實際可用略少);GET、HEAD 不能帶 body
timeoutMs1000–60000,預設 15000;超出範圍會被夾到範圍內
url最多 8192 字

以下標頭由容器決定,你設定的會被直接忽略(不報錯):Host、Cookie、Cookie2、Connection、Content-Length、Transfer-Encoding、TE、Trailer、Upgrade、Keep-Alive、Expect、Origin、Referer、Via、Accept-Encoding,以及 Proxy-*、Sec-* 開頭的標頭。

帶 body 的請求以 Content-Length 送出(不用 chunked),可以直接上傳到 S3/GCS 的預簽網址(文字內容)。

登入身分:sdk.auth.getSession ​

ts
const session = await sdk.auth.getSession();
// { userId, nickname, avatar, token, expiresAt }
欄位說明
userId目前登入者的 ID
nickname暱稱
avatar頭像網址;沒有頭像時為 null
token只對你這個小程序有效的短效 token
expiresAttoken 到期時間(ISO 8601,UTC)
  • 容器在小程序開啟時就預先簽發 token,第一次呼叫通常不用等網路。
  • token 剩不到 1 分鐘就會自動換新;每次需要時直接呼叫 getSession() 即可,不要自己存起來。
  • 換帳號後舊 token 失效,保活的實例也會被釋放。

在後端驗證 ​

前端拿到的 userId 只能拿來顯示。後端一律以 token 判斷身分:

小程序 ── Authorization: Bearer <token> ──▶ 你的後端 ── 驗證 token ──▶ IM 平台
                                                    ◀── userId ────
  • token 綁定你的小程序 ID:其他小程序的 token 拿來呼叫你的後端會驗證失敗。
  • 過期或無效時回 401。

驗證介面 ​

在後台「成员与体验 → 服务端密钥」產生密鑰(只顯示一次,請存在後端的機密設定裡,不要放進小程序),然後:

http
POST https://<平台網址>/api/open/session/verify
Authorization: Bearer <服務端密鑰>
Content-Type: application/json

{ "token": "<小程序送來的 token>" }
回應說明
200 { "appId", "userId", "expiresAt" }有效;以 userId 作為使用者身分
401 { "error": { "code": "invalid_token" } }token 無效、過期或不屬於你的小程序:回 401 給小程序
401 { "error": { "code": "bad_secret" } }服務端密鑰錯誤或已重新產生
  • 可以依 expiresAt 快取驗證結果,減少請求;不要快取超過到期時間。
  • 重新產生密鑰後舊密鑰立即失效,請先更新後端設定再產生。

401 時重新簽發 ​

後端回 401(例如 token 被撤銷、裝置時間不準),用 refresh: true 強制重新簽發,只重試一次:

ts
async function fetchWithAuth(url: string) {
  for (let attempt = 0; ; attempt++) {
    const { token } = await sdk.auth.getSession({ refresh: attempt > 0 });
    const res = await sdk.http.fetch(url, { headers: { Authorization: `Bearer ${token}` } });
    if (res.status === 401 && attempt === 0) continue;
    return res;
  }
}

refresh 需要容器 1.2.0。

其他連線方式 ​

  • 外部網頁:小程序內不能導向外部網址(會被擋下)。要讓使用者看外部網頁時,用 sdk.system.openUrl 在外部瀏覽器開啟(只限 https)。
  • iframe:不能嵌入任何網頁(CSP frame-src 'none')。
  • WebSocket、Server-Sent Events:目前沒有提供對應的能力,也不保證直接連線可用。