Appearance
域名總覽
為什麼需要域名探測?
App 的域名隨時可能被封鎖或無法訪問。為了讓用戶始終能正常使用,App 內建了一套域名探測機制:啟動時同時嘗試多個候選域名,誰先回應就用誰。如果全部候選都掛了,還有 OSS 兜底地址作為最後防線。
這份文件盤點 App 裡所有域名的來源、替換機制、和 fallback(備用值)。
排查線上問題看哪份?
看 st_domain_config.json。線上(Release)環境的域名探測流程全部走這份檔案。domain.json 只影響開發人員本地 DEBUG 模式,與線上用戶無關。詳見 App 啟動 — 域名探測流程。
域名來源總覽
App 裡用到的域名來自四種不同來源,不要搞混:
| 來源 | API / 機制 | 涵蓋範圍 |
|---|---|---|
| domain/list/v2 | api/forehead/system/domain/list/v2 | 下面 UrlType 表格的 16 個 type,是主要的域名系統 |
| getXJConfig | 小金配置 API | FB 體育 (fbSportPath)、UP 體育 (upSportPath) |
| 場館登入回應 | OB 登入 API | OB 體育 (apiDomain) |
| 外部 SDK / 寫死 | 無 API,純寫死在 code | JPush 推送、阿里雲日誌、備用 IP |
來源一:domain/list/v2(UrlType 體系)
來源
api/forehead/system/domain/list/v2 回傳的 data 陣列,每個物件有 type 欄位。App 用 BBUrlListModel 解析後存入對應 array,再由 IFMainSwitch.m 的 getter 取用。
API Request / Response 格式
Request:POST /api/forehead/system/domain/list/v2(無 Body)
關鍵 Header:pid: bb、app-type: 1、os-type: 3、sign、timestamp、device-id
Response:
json
{
"code": 1,
"data": [
{ "type": 1, "domain": "https://...", "serviceType": 0, "clientType": 0 }
]
}所有 type 都是取 domain 欄位。type 15、16 額外用 serviceType 判斷客服種類:
| serviceType | 含義 | 存入值 |
|---|---|---|
| 1 | 智齒客服 | 存入實際 domain URL |
| 2 | LiveChat | 存入 "LiveChat" 標記 |
| 3 | ST 客服 | 存入 "SDK" 標記 |
| 4 | ST 客服 SDK | 存入 "SDK" 標記(與 3 行為相同,code 註解不同但結果一樣) |
實際 API 回應範例(2026-04-13 Proxyman 抓包)
從模擬器實際抓到的回應,6 個候選域名同時發出請求,最快的 106ms 勝出:
| 候選域名 | 回應時間 |
|---|---|
m-ygha39p0x3.dpaw63qmfd14.com | 106ms(勝出) |
m-ovnq29u5b3.wejaazhp47.com | 231ms |
m-suxn33i1i0.vafrazwu44.com | 234ms |
m-uthb76i2c2.zljzazmm59.com | 277ms |
m-djwn09z3m2.vshwazor54.com | 317ms |
m-ayhc45u7p3.iabf52qmhg7.com | 2909ms |
回應 data 陣列包含以下 type(部分):
| type | domain | serviceType |
|---|---|---|
| 0 | https://m.bbtyv33.com | 0 |
| 1 | 4 個主域名(如 m-c66a025qc1sfbx5h4.dfvfxolj102.com) | 0 |
| 2 | wss://pushi32e54ih.bbpushl1ooe.com | 0 |
| 3 | https://eacjxoip129.com | 0 |
| 4 | https://m.iballbet.com | 0 |
| 6 | wss://chat-i5gfn52ai5sc.sldd28qmzs18.com | 0 |
| 7 | https://chat.abywxodlchat6.com | 0 |
| 9 | https://20.24.110.65 | 0 |
| 12 | https://mf.bbtyv3.com | 0 |
| 13 | https://23.97.72.178/login | 3 |
| 14 | https://23.97.72.178/login | 3 |
| 15 | "1" | 4(ST客服SDK → 存入 "SDK" 標記,domain 值不使用) |
| 16 | https://23.97.72.178/login | 3 |
| 17 | SEO 域名 | 0 |
| 18 | PXDD 域名 | 0 |
| 21 | https://api.asia-fb.com | 0 |
| 30 | activity-h5 域名 | 0 |
| 31 | https://23.97.72.178 | 0 |
| 35 | sport-info-h5-1c5a6x(subdomain 片段,非完整 URL) | 0 |
| 36 | activity-h5-3aceg36k(subdomain 片段,非完整 URL) | 0 |
觀察重點:
- Type 1 回傳多筆,存入
appMainUrlArray後寫入 BTHostList.plist - Type 13、14、31 伺服器有下發但 App 不處理(見下方「伺服器有下發但 App 不處理」段落)
- Type 15 的 domain 是字串
"1",因為 serviceType = 4 會存入"SDK"標記,domain 值被忽略 - Type 35、36 回傳的不是完整域名,是 subdomain 片段,需要跟主域名拼接
有在用的 UrlType(16 個)
| Type | 名稱 | 用途 | 本地 fallback |
|---|---|---|---|
| 1 | AppMainUrl | 手機主域名 | realese_domains 第一個 |
| 2 | PushUrl | 推送域名 | 空(伺服器 → 從主域名拼接 → 寫死值,三層 fallback) |
| 4 | SportUrl | 體育 Node 服務 | https://www.fldsj.cc |
| 5 | MatchImageUrl | 球隊圖標 | http://teamicon.jswswl.com/ |
| 6 | ChatSocketUrl | 聊天室 | wss://chat.uubody.com:9507 |
| 7 | ChatReportUrl | 聊天舉報 | https://ws2-newchat.bbtstxqm7.com |
| 8 | MatchResultUrl | 賽果 | http://matchresult.jswswl.com |
| 9 | ZhiChiUrl | 智齒客服 | https://103.74.194.51/chat/h5/index.html |
| 10 | LiveChatUrl | LiveChat 客服 | https://103.74.194.51/chat/h5/index.html |
| 11 | SportInformationUrl | 體育資訊 | https://sport-info-h5.bbmobilepro01.com(伺服器 → type 35 拼接 → 寫死值) |
| 12 | ProxyUrl | 代理域名 | 空 |
| 15 | ServiceMainLine | 主線客服 | client_domain.json |
| 16 | ServiceMinorLine | 次線客服 | client_domain.json |
| 17 | SEOUrl | SEO 域名 | 空 |
| 18 | PXDDUrl | 雷速 PXDD | 空 |
| 30 | ActivityUrl | 活動跳轉 | https://activity-h5.bbmobilepro01.com |
開發者參考:Model Property 與 Getter 對照
| Type | 存入 Model Property | Getter 方法 |
|---|---|---|
| 1 | appMainUrlArray | getUrlStrWithType: |
| 2 | pushUrlArray | getPushUrl() |
| 4 | sportUrlArray | getNodeServiceHost() |
| 5 | mathchImageUrlArray | getTeamIconHost() |
| 6 | chatSocketUrlsArray | getChatSocketUrl1/2() |
| 7 | chatReportUrlArray | getChatReportUrl() |
| 8 | matchResultUrlArray | getMatchResultHost() |
| 9 | zhiChiUrlArray | getZhiChiKefuUrl() |
| 10 | liveChatUrlArray | getLiveChatKefuUrl() |
| 11 | sportInformationUrlArray | getSportInformationUrl() |
| 12 | procyUrlArray | getProcyUrl() |
| 15 | chatMainUrlArray + serviceType | 寫入 AppDomain.shared.serviceDomain |
| 16 | chatMirrorlArray + serviceType | 存入 BBUrlListModel |
| 17 | seoUrlArray | getSEOUrl() |
| 18 | pxddUrlArray | getPXDDUrl() |
| 30 | activityUrlArray | getActivityUrl() |
間接使用的 UrlType(2 個)
這些 type 沒有獨立的 getter,但會被其他功能內部讀取:
| Type | 名稱 | 存入 Model Property | 誰在用 |
|---|---|---|---|
| 21 | SpeedSportUrl | speedSportArray | FB/UP 體育競速探測時,從這裡取備用域名列表 |
| 35 | PiazzaUrl | piazzaUrlArray | getSportInformationUrl() 內部拼接用 |
沒有使用的 UrlType(3 個)
| Type | 名稱 | 存入 Model Property | 備註 |
|---|---|---|---|
| 0 | PcUrl | — | PC 域名,App 裡完全沒引用 |
| 3 | AppDownLoadUrl | appDownLoadUrlArray | App 下載域名,code 註解「不需要」 |
| 36 | H5Url | h5UrlArray | H5 拼接,有存入 model 但無人使用 |
伺服器有下發但 App 不處理的 UrlType(3 個)
伺服器有回傳,但 App code 裡沒有對應的解析邏輯,會被靜默忽略
從 Proxyman 實際抓包觀察到伺服器確實有下發這些 type:
| Type | 實際回傳的 domain | serviceType | 推測用途 |
|---|---|---|---|
| 13 | https://23.97.72.178/login | 3(ST客服) | 可能是其他平台(PC/H5)的客服入口 |
| 14 | https://23.97.72.178/login | 3(ST客服) | 同上 |
| 31 | https://23.97.72.178 | 0 | 用途不明 |
未定義的 UrlType(10 個)
type 19, 20, 22~29, 32~34 — 目前伺服器未下發,App 也無對應處理。
來源二:getXJConfig API(體育域名)
來源
小金配置 API (getXJBetConfig) 回傳的 response 中包含 fbSportPath 和 upSportPath,App 存入 UserDefaults。
| 域名(fallback) | 用途 | API 欄位 | 替換機制 |
|---|---|---|---|
https://api.inf18.com | FB 體育 API | fbSportPath | API 下發 → 存 UserDefaults + 競速探測 |
https://api.nsvip7.com | UP 體育 API | upSportPath | 同上 |
FB / UP 優先順序:property(記憶體)→ UserDefaults(API 下發存的)→ 寫死值
競速探測(為什麼需要?):當 FB/UP 體育的 API 請求失敗時(域名可能被封),App 不會直接報錯,而是自動從 domain/list/v2 回來的 UrlType 21(SpeedSportUrl)備用域名列表中,同時探測所有域名,第一個回應的就作為新域名寫入 property + UserDefaults,後續請求自動切過去。10 秒內只觸發一次,避免重複探測。
來源三:場館登入回應(OB 體育)
來源
OB 體育場館登入成功後,從回應的 OBDomainModel 取得 apiDomain,寫入 IFMainSwitch.obSportHost。
| 域名(fallback) | 用途 | 替換機制 |
|---|---|---|
https://api.sportxxx278gwf4.com | OB 體育 API | OB 登入回應 apiDomain → 寫入 property |
OB 優先順序:property(登入回應寫的)→ 寫死值
來源四:寫死在 code(無法動態替換)
以下域名掛了只能發版
| 域名 | 用途 | 原因 |
|---|---|---|
http://push.bbtstxqm7.com:9101 | 測試推播 HTTP | 測試環境專用,無 UrlType 對應 |
cn-guangzhou.log.aliyuncs.com | 阿里雲日誌 | 基礎設施配置,純寫死 |
https://34.96.197.27:8802 | 備用 IP | getIPList() 純寫死回傳 |
域名探測配置(st_domain_config.json)— 正式發布用
檔案路徑:BBSport/Tools/STDomainListManager/st_domain_config.json
Release 模式下的域名探測完全依賴這份配置。
Release 候選域名(realese_domains)
線上用戶域名探測的候選清單,首次安裝時是唯一的域名來源。
https://m-nu42sdu3xfca6.kzpw72mndq19.com
https://m-ayhc45u7p3.iabf52qmhg7.com
https://m-4ytsuxn33i1i0ca3.vafrazwu44.com
https://m-djwnsdfs09a6z3m2.vshwazor54.com
https://m-5xov436trc5b0j.wejaazhp47.com
https://m-uthb76i2c2.zljzazmm59.comDebug 候選域名(debug_domains)
定義在配置中但 code 裡未讀取 debugHosts,實際 DEBUG 模式用的是 AppDomain.shared.root。
https://m.bbmobileproaz.com
http://m.bbtstxqm7.com
https://m.bbuat2021.com
http://m.bbgamedev.com
http://m.bbsama.com
http://www.bbdev.com
http://www.seeknewt.comOSS 兜底地址(aliyun_oss_url)
寫死且無法被伺服器更新
所有候選域名都掛時的最後防線,App 會去這些 OSS 地址拿一份新的域名清單再試。這 3 個地址全掛 = App 完全無法聯網,只能發版。
https://ui26ftj02lvf.qodmazcn53.com/bb99/bbpub.json
https://cu02ftj02lvf3.pukyazpv57.com/bb99/bbpub.json
https://ou34ftj02lvf2.qkdoazbi55.com/bb99/bbpub.json探測 API 路徑
/api/forehead/system/domain/list/v2主域名入口(domain.json)
檔案路徑:BBSport/Tools/Domain/M/domain.json
App 啟動 Step 1 讀取,設定 AppDomain.shared.root 的初始值。DEBUG 模式下直接用這個不探測。
| 域名 | 環境 |
|---|---|
https://m.bbtyv16.com | 正式 |
https://m.bbuat2021.com | UAT |
http://m.bbtstxqm7.com | 測試 |
AppDomain 在 Release 也有人用
AppDomain.shared.root 不是只給 DEBUG 用。以下 Release code 也直接讀它:
CustomerChatManager.swift:210, 819— 客服 URL 拼接ExponentView.swift:27— 體育指數
AppDomain.shared.serviceDomain 會被伺服器回應的 UrlType 15 動態更新。
客服域名(client_domain.json)
檔案路徑:BBSport/Tools/ClientDomain/client_domain.json
可被伺服器 UrlType 15(主線客服)和 16(次線客服)動態替換。
測試環境
| 用途 | 域名 |
|---|---|
| Domain | https://domain.bbkefutest.com |
| API | http://api.bbkefutest.com |
| Socket | wss://server.bbkefutest.com |
| Logger | https://logger.bbkefutest.com |
UAT 環境
| 用途 | 域名 |
|---|---|
| Domain | https://domain.uatbbkf.com |
| API | https://api.uatbbkf.com |
| Socket | wss://chat.bbkefu88.com/ws |
| Logger | https://logger.bbkefu88.com |
正式環境
| 用途 | 域名 |
|---|---|
| Domain | https://47.243.66.137:8080(IP 直連) |
| API | https://api.bbkefu88.com |
| Socket | wss://chat.bbkefu88.com/ws |
| Logger | https://logger.bbkefu88.com |
JPush 極光推送(AppDelegate+JPPush.swift)
檔案路徑:BBSport/AppDelegate/AppDelegate+JPPush.swift
外部 SDK 管理,不走 UrlType 體系,無法被伺服器替換。
| 值 | 用途 |
|---|---|
conn.bwqh56sxfz19.com | 推送連線 Host |
54.46.41.147 | 推送連線 IP |
5000 | 推送連線 Port |
https://report.bwqh56sxfz19.com/v3/report | 推送回報 URL |
https://report.bwqh56sxfz19.com/v1/user | Badge 回報 URL |
三方服務金鑰(寫死在 IFMainSwitch.m)
注意:以下為寫死在 code 裡的金鑰
| 金鑰 | 值 | 用途 |
|---|---|---|
| Aliyun AccessKeyID | LTAI5t****U2a7 | 阿里雲日誌服務 |
| Aliyun AccessKeySecret | hwNNU****5u6U | 阿里雲日誌服務 |
| NetEase Verify Code ID | deca7****9591 | 網易驗證碼 |
| NetEase Product Number | YD001****5826 | 網易驗證碼 |
| Aliyun EMS AppKey | 3355****9260 | 阿里雲郵件服務 |
| Aliyun EMS AppSecret | 937dd****dcb0 | 阿里雲郵件服務 |
完整值請查看 BBSport/Tools/RouterComponent/Classes/Main/IFMainSwitch.m。