網路與登入身分
宣告網域
小程序只能連 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/XMLHttpRequest | CSP 只放行清單內的網域,但會受 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):
| 參數 | 規則 |
|---|---|
method | GET、POST、PUT、PATCH、DELETE、HEAD(大小寫不拘),預設 GET |
headers | 最多 50 個;名稱只能是 token 字元(英數與 !#$%&'*+.^_`|~-),值只能是可見 ASCII 與 tab(不能有中文或換行,需要時先編碼) |
body | 文字,最多 1 MB(整則呼叫訊息上限也是 1 MB,實際可用略少);GET、HEAD 不能帶 body |
timeoutMs | 1000–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 |
expiresAt | token 到期時間(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:目前沒有提供對應的能力,也不保證直接連線可用。