檔案概述
訊息裡的圖片、語音、影片和檔案,使用者和群的頭像、聊天室封面,以及群檔案,都可以上傳到本服務儲存。檔案內容由上傳方直接寫入物件儲存,下載時也直接從物件儲存(或 CDN)讀取,不經過 IM 服務的介面。
| 要做什麼 | 見 |
|---|---|
| 上傳一張圖片併發成圖片訊息 | 上傳圖片併傳送圖片訊息 |
| 給使用者設定頭像 | 為使用者設定頭像 |
| 下載附件、群檔案 | 換取下載地址 |
| 查詢、刪除檔案,看儲存用量 | 下載與管理檔案 |
| 瞭解各用途的大小上限、誰能下載、保留多久 | 本頁:檔案的用途 |
每個檔案上傳時指定用途(purpose),用途決定大小上限、誰能下載和保留多久。上傳完成後得到兩種地址之一:
| 地址 | 用於 | 能直接開啟嗎 | 怎麼用 |
|---|---|---|---|
| 檔案地址 | 訊息附件、群檔案 | 不能,要先換取短期有效的下載地址 | 寫進訊息的 body |
| 公開地址 | 使用者頭像、群頭像、聊天室封面 | 能,任何人都能訪問 | 填進使用者、群或聊天室資料的 avatar_url |
客戶端上傳
使用者在客戶端傳送圖片、更換頭像、上傳群檔案時,由客戶端用 User Token 直接呼叫與 OpenAPI 相同的上傳介面(路徑字首為 /client/v1/media,不能指定 owner,並按使用者限制頻率),SDK 釋出後由 SDK 封裝。本節只介紹你的服務端透過 OpenAPI 呼叫的介面。
檔案的用途
用途 purpose | 內容 | 允許的型別 kind | 大小上限 | 誰可以下載 | 保留多久 |
|---|---|---|---|---|---|
attachment 訊息附件 | 圖片、語音、影片、檔案訊息中的檔案 | image、voice、video、file | 執行策略 max_upload_bytes,預設 100 MB;圖片另不超過 20 MB,語音另不超過 5 MB | 你的服務端;本應用任何登入的使用者(持有檔案地址即可) | 從上傳時起 attachment_retention_days 天,預設 30 天 |
user_avatar 使用者頭像 | 使用者資料中的頭像 | image | 5 MB | 任何人(公開地址) | 被使用期間一直保留,見下文 |
group_avatar 群頭像 | 群資料中的頭像 | image | 5 MB | 任何人(公開地址) | 同使用者頭像 |
chatroom_avatar 聊天室封面 | 聊天室資料中的封面 avatar_url,見封面 | image | 5 MB | 任何人(公開地址) | 同使用者頭像;聊天室解散 7 天后刪除 |
group_file 群檔案 | 群的共享檔案 | image、video、file | 同訊息附件 | 你的服務端;群的當前成員 | 預設不過期,可以用 group_file_retention_days 設定天數;群解散後刪除 |
執行策略中的各項見執行策略。此外:
檔名:建立上傳時的
name,1 到 255 個字元,規則與檔案訊息的name相同(不能只有空白,不能包含/、\、控制字元和改變文字方向的字元)。型別為file的檔案和群檔案必須填寫,下載時作為儲存的檔名。群檔案:每個群最多 1000 個群檔案。執行策略
group_file_enabled關閉時,群成員不能在客戶端上傳群檔案,你的服務端仍然可以上傳。客戶端只有當前的群成員能檢視群檔案列表和下載,離開群之後不能再下載。頭像(包括聊天室封面)按“是否正在被使用”保留:
情況 頭像檔案 上傳後 24 小時內沒有設定到資料中 自動刪除 資料中的頭像被換成其他地址或清空 7 天后刪除,留給還快取著舊資料的客戶端 使用者頭像設定到了其他使用者(不是上傳時的 owner)的資料中不算使用。群頭像算第一個用上它的群,封面算第一個用上它的聊天室 使用者被刪除 他的使用者頭像隨即刪除 群解散 群頭像保留 聊天室解散 7 天后封面刪除 歸屬:檔案屬於上傳它的應用,其他應用的使用者和服務端都無法下載。
檔案地址
訊息附件和群檔案完成上傳後得到檔案地址,圖片另有縮圖地址:
https://im.example.com/media/v1/f/{file_id}/{secret}
https://im.example.com/media/v1/f/{file_id}/{secret}/thumbfile_id是檔案 ID,查詢檔案、刪除檔案等介面用它指定檔案;secret是 22 個字元的隨機金鑰,無法猜出。- 地址的主機由服務的部署決定,不一定與 OpenAPI 的接入地址相同。請原樣使用介面返回的
url和thumbnail_url,不要自己拼接或修改,帶上查詢引數的地址也不再被識別為檔案地址。 - 檔案地址固定不變,可以長期儲存、寫進訊息、作為客戶端快取的鍵。檔案過期或被刪除後,地址仍然不變,只是不能再下載。
檔案地址不能直接下載。直接開啟檔案地址返回 401 unauthenticated,App Token 也不能直接請求它。下載時要先換取下載地址:
你的服務端:呼叫換取下載地址,一次最多 100 個地址,可以下載本應用的全部附件和群檔案。
客戶端:使用者用 User Token 換取(與 OpenAPI 相同的批次介面
POST /client/v1/media/download-urls),或者帶著 User Token 直接請求檔案地址GET /media/v1/f/{file_id}/{secret}(縮圖為…/thumb),服務端校驗後返回302,跳轉到下載地址:httpGET /media/v1/f/99606093402996736/DC0neNm6HBbxGW9bN6g_iA/thumb HTTP/1.1 Host: im.example.com Authorization: Bearer <User Token> HTTP/1.1 302 Found Cache-Control: no-store Location: https://storage.example.com/im-private/t99604914749046784/a99604957103128576/m/99606093402996736_thumb?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20261002T203000Z&X-Amz-Expires=5400&X-Amz-SignedHeaders=host&X-Amz-Signature=52ca87a0...移動端的圖片載入庫可以這樣使用,並按不變的檔案地址快取圖片。跟隨跳轉時不能把
Authorization請求頭帶到下載地址:物件儲存會因請求同時帶有簽名引數和Authorization而拒絕(返回400),User Token 也會洩露給儲存服務。多數 HTTP 庫跳轉到其他主機時會自動去掉它。檔案地址不返回跨域響應頭,網頁中請用換取介面。
誰可以換取:
| 呼叫方 | 訊息附件 | 群檔案 |
|---|---|---|
| 你的服務端(OpenAPI) | 全部 | 全部,不檢查群成員身份 |
| 客戶端(本應用登入的使用者) | 任何使用者,不檢查他是否在附件所在的會話中 | 當前的群成員,其他使用者得到 not_group_member |
附件不按會話判斷許可權:同一個地址會隨轉發出現在其他會話中,而地址中的金鑰無法猜出,持有地址的使用者本來就看到過這條訊息。客戶端換取下載地址(包括直接請求檔案地址)每個使用者每分鐘最多 600 個檔案,超出時得到 429 rate_limited,details.reason 為 download_rate。
換取的結果:可用的檔案得到下載地址;檔案已過期或已被刪除的得到 file_expired(直接請求檔案地址時為 410),被遮蔽的得到 file_blocked(403),不是本應用的檔案、金鑰不對或還在上傳中的得到 not_found(404)。
只接受本服務的地址
應用在執行策略中開啟 media_url_only 後,使用者在客戶端傳送圖片、語音、影片和檔案訊息時,地址只能是本服務的檔案地址(或 media_allowed_hosts 中的主機);客戶端設定的使用者頭像、群頭像和聊天室封面只能是本應用的頭像公開地址(或 media_allowed_hosts 中主機的 https 地址)。你的服務端寫入的地址不受這項限制,見執行策略。
縮圖地址
圖片型別的訊息附件和群檔案有縮圖地址,即檔案地址加 /thumb,指向長邊不超過 480 畫素的縮圖,用於在訊息列表中顯示。原圖本身不超過 480 畫素且不超過 100 KB 的,縮圖就是原圖。其他型別的檔案沒有縮圖,請求 /thumb 得到 not_found。
公開地址
頭像(使用者頭像、群頭像和聊天室封面)完成上傳後得到公開地址,任何人不需要登入就能直接訪問:
https://cdn.example.com/t99604914749046784/a99604957103128576/u/99606376459796480_thhts5lb.jpg頭像要在會話列表、好友列表、群成員列表中大量顯示,每個都換取一次下載地址的代價太大,所以儲存在公開的儲存中。公開地址同樣固定不變,把它填進使用者、群或聊天室資料的 avatar_url 即可,響應頭帶 Cache-Control: public, max-age=86400,CDN 和客戶端可以快取一天。公開地址不需要也不能換取下載地址。
上傳流程
上傳分三步,見上傳檔案:
- 建立上傳:提交用途、型別、大小和檔名(群檔案另帶群 ID),服務端檢查用途和型別、大小上限和應用的儲存額度,返回檔案 ID 和上傳地址。
- 上傳內容:直接向物件儲存上傳檔案內容。
- 單次上傳:不超過 32 MB 的檔案,按返回的上傳地址一次
PUT寫入; - 分片上傳:超過 32 MB 的檔案,每 16 MB 一片(最後一片可以更小),最多 128 片。按需索取各片的上傳地址,各片可以並行、按任意順序上傳;網路中斷後可以查詢已上傳的分片,只補傳缺少的分片。
- 單次上傳:不超過 32 MB 的檔案,按返回的上傳地址一次
- 完成上傳:服務端核對上傳的大小、按檔案內容識別格式、處理圖片,透過後檔案變為可用,返回檔案物件,其中有檔案地址(或頭像的公開地址)、縮圖地址、寬高和大小。
是單次上傳還是分片上傳由服務端按 size 決定。頭像、圖片和語音的大小上限都不超過 20 MB,總是單次上傳;只有影片和 file 型別的檔案可能分片上傳。
- 有效期:單次上傳要在建立後 1 小時內完成,分片上傳 24 小時內;每片的上傳地址 1 小時內有效,過期後可以重新索取。到期仍未完成的上傳自動作廢,已上傳的內容隨後刪除。不再需要時可以主動取消上傳。
- 重複提交:完成上傳可以重試,已完成的返回第一次的結果。建立上傳不去重,每次都會建立一個新的檔案 ID,沒有完成的上傳過期後自動刪除,不計入儲存用量。
- 只有建立者能繼續:透過 OpenAPI 建立的上傳,只能由同一個應用透過 OpenAPI 繼續上傳、完成或取消(可以使用該應用的任何 App Token);客戶端和控制檯建立的上傳,OpenAPI 的上傳介面查詢不到。
- 上傳中的檔案不能下載,也不計入儲存用量。
格式檢查與圖片處理
完成上傳時,服務端讀取檔案開頭的內容識別格式,不採用建立上傳時宣告的 content_type,也不看檔名的字尾。各型別允許的格式(括號中為識別後記錄的 content_type):
型別 kind | 允許的格式 |
|---|---|
image | JPEG(image/jpeg)、PNG(image/png)、GIF(image/gif)、WebP(image/webp) |
voice | AAC(audio/aac)、M4A 等 MP4 容器(audio/mp4)、MP3(audio/mpeg)、AMR(audio/amr)、3GP(audio/3gpp)、Ogg(audio/ogg)、WAV(audio/wav)、WebM(audio/webm) |
video | MP4(video/mp4)、MOV(video/quicktime)、WebM(video/webm)、3GP(video/3gpp) |
file | 任意格式。能識別的記為對應的格式,如 PDF 為 application/pdf;其他按內容判斷,如純文字為 text/plain;無法判斷的為 application/octet-stream |
格式不符合型別的,完成上傳失敗,返回 400 invalid_argument,details.reason 為 unsupported_type,details.content_type 為識別出的格式,要重新建立上傳。HEIC 等其他格式的圖片請先轉換為 JPEG,或作為 file 上傳;SVG、HTML 這類可以包含指令碼的內容只能作為 file 上傳。
圖片(型別為 image 的訊息附件和群檔案):
- 寬乘高不能超過 5000 萬畫素,否則完成上傳失敗(
image_too_large);無法解碼的圖片同樣失敗(invalid_image)。 - 去掉 EXIF、XMP 等後設資料(其中可能有拍攝地點、裝置型號),包括 PNG 的文字塊和 GIF 的註釋,保留方向資訊、顏色配置和動圖的迴圈次數。圖片不重新壓縮,畫質不變,但儲存後的大小可能比原檔案略小,請以完成上傳返回的
size為準。 width、height是按方向資訊旋轉之後的顯示寬高。- 生成長邊不超過 480 畫素的縮圖,格式為 JPEG,有透明畫素的為 PNG;GIF 取第一幀。原圖長邊不超過 480 畫素且不超過 100 KB 的,以及動畫 WebP,縮圖就是原圖。
- 計算儲存內容的 SHA-256,即檔案物件中的
sha256。
頭像:縮放為長邊不超過 640 畫素(更小的不放大),重新編碼為 JPEG,有透明畫素的為 PNG;GIF 取第一幀;去掉全部後設資料。上傳的原圖不保留,檔案物件中的 size、width、height 和 sha256 都是處理後的值。
語音、影片和 file 型別的檔案(包括作為 file 上傳的圖片)不做任何處理:不轉碼、不生成封面、不去除後設資料(如影片中的拍攝地點),也不檢測病毒。需要時請在上傳前處理,影片的封面請擷取一幀作為圖片另外上傳。
下載時的響應頭:下載地址返回識別出的 Content-Type。圖片、語音和影片可以在瀏覽器中直接顯示或播放;file 型別的檔案和全部群檔案帶 Content-Disposition: attachment 和原檔名,瀏覽器會下載而不是開啟。
下載地址
換取得到的下載地址是物件儲存(或 CDN)的簽名地址,直接 GET 即可,不需要也不能帶 Authorization 請求頭,支援 Range 請求(斷點續傳、影片拖動進度)。
- 有效期 60 到 90 分鐘:簽名時刻按 30 分鐘對齊,有效 90 分鐘,到期時間見換取結果中的
expires_at。同一個檔案在同一個 30 分鐘內換到的地址完全相同,瀏覽器和 CDN 可以按地址快取。 - 請在到期前重新換取,不要儲存下載地址,也不要把它寫進訊息:訊息中應該儲存不變的檔案地址。
- 縮圖地址換到的是縮圖的下載地址。
- 下載地址洩露後,他人在到期前也能用它下載,請不要轉發。
過期與刪除
檔案在以下情況下被刪除:
| 情況 | 刪除的檔案 |
|---|---|
| 超過保留期 | 上傳超過 attachment_retention_days 天(預設 30 天)的訊息附件;設定了 group_file_retention_days 時,超過天數的群檔案。保留期從上傳時算起,不是從傳送訊息時算起。檔案物件中的 expires_at 按應用當前的保留天數算出,到期後由後臺任務刪除,可能比它晚一些(通常不超過 1 小時);調短保留天數後,按新的天數已經過期的檔案隨即刪除 |
| 頭像不再使用 | 上傳後 24 小時內沒有使用的頭像;被替換 7 天后的頭像;聊天室解散 7 天后的封面 |
| 刪除使用者 | 他的使用者頭像。應用開啟了刪除使用者時擦除訊息(erase_messages_on_user_delete)的,所屬使用者為他的訊息附件和群檔案也一起刪除 |
| 解散群 | 這個群的全部群檔案,群頭像保留 |
| 主動刪除 | 你的服務端刪除檔案、在控制檯刪除,或客戶端的群主、管理員、上傳者刪除群檔案 |
檔案被刪除後,訊息本身仍然保留,body 中的地址也不變;撤回訊息不會刪除附件。換取下載地址時得到 file_expired,直接請求檔案地址返回 410,客戶端應顯示“檔案已過期”。刪除的記錄再保留約 30 天,之後換取得到 not_found,客戶端按同樣的方式顯示即可。
刪除前已經換取的下載地址,在檔案內容從儲存中刪除之前(約 10 分鐘)仍可能使用;部署了 CDN 時,CDN 上已快取的內容最長可用到下載地址到期。頭像的公開地址在 CDN 上的快取最長 1 天后失效。
違規檔案的遮蔽
違規的檔案會被遮蔽:內容安全的事後稽核判定違規,或稽核人員確認違規時,按平臺規則或你的規則遮蔽;平臺也可以直接遮蔽。被遮蔽後:
| 方面 | 結果 |
|---|---|
| 下載 | 換取下載地址得到 file_blocked,直接請求檔案地址返回 403,縮圖同樣;已換取的下載地址通常 1 分鐘內失效(CDN 上已快取的最長可用到下載地址到期) |
| 頭像 | 從公開地址移除(通常 1 分鐘內),CDN 快取最長 1 天后失效 |
| 檔案內容 | 作為證據保留 180 天后刪除;期間可以解除遮蔽,解除後恢復可用(已超過保留期的隨後按保留期刪除) |
| 誰能解除 | 按你的規則遮蔽的(block_rule_source 為 tenant):你的稽核人員把稽核記錄改為無違規時自動解除。按平臺規則的(platform):只能由平臺解除 |
| 刪除與用量 | 你不能刪除被遮蔽的檔案(403 file_blocked);它不再計入儲存用量 |
| 引用它的訊息和資料 | 遮蔽本身不修改。內容安全處置時會同時撤回訊息、清除被遮蔽的頭像;其他情況請自行撤回訊息或修改資料 |
查詢檔案時,被遮蔽的檔案 status 為 blocked,並給出遮蔽的時間、原因和依據的規則。對平臺的遮蔽如有異議請聯絡我們。
儲存用量與額度
用量是應用中可用的檔案(status 為 active)佔用的空間和檔案數,按用途分別統計,圖片包括縮圖。上傳中、已刪除和被遮蔽的檔案不計入。用查詢儲存用量獲取,控制檯的“檔案儲存”中也可以檢視。
額度:平臺開啟檔案儲存額度限制時,取平臺給應用的儲存配額(預設 1024 GB,1 GB 按 230 位元組計)與套餐儲存容量中較小的一個,見套餐與賬單。關閉限制時不限額度,不拒絕上傳,也不對儲存量計費。
- 超額時:建立上傳時,已用空間加上這次的
size超過額度,返回409 limit_exceeded(storage_quota,details.limit_bytes和details.used_bytes為額度和已用位元組數)。只拒絕新上傳,不影響下載,也不刪除已有檔案。 - 軟上限:同時進行的多個上傳都在建立時檢查,最終用量可能略超額度。
- 怎麼辦:刪除不再需要的檔案,或縮短附件的保留天數;需要更大額度時更換套餐或聯絡我們。
資料結構
檔案物件
完成上傳、查詢檔案、查詢群檔案列表時返回檔案物件:
| 欄位 | 型別 | 說明 |
|---|---|---|
file_id | String | 檔案 ID |
purpose | String | 用途:attachment、user_avatar、group_avatar、chatroom_avatar、group_file,見檔案的用途 |
kind | String | 型別:image、voice、video、file |
status | String | 狀態:pending 上傳中 / active 可用 / blocked 已遮蔽 / deleted 已刪除(包括上傳失敗、取消和過期的上傳) |
url | String | 訊息附件和群檔案為檔案地址,頭像和聊天室封面為公開地址。上傳中和已刪除的檔案也有地址,但不能下載 |
thumbnail_url | String | 縮圖地址,只有圖片型別的訊息附件和群檔案有,其他為 null;上傳中和已刪除的檔案也為 null |
name | String | 檔名,建立上傳時給出,沒有為 null |
content_type | String | 按檔案內容識別出的格式,如 image/jpeg,見格式檢查與圖片處理。完成上傳之前為 null |
size | Number | 大小,單位為位元組。圖片為去掉後設資料後的大小,頭像為處理後的大小,其他為上傳的大小;完成上傳之前為建立時宣告的大小 |
width | Number | 圖片和頭像的寬度,畫素;其他為 null |
height | Number | 圖片和頭像的高度,畫素;其他為 null |
owner | String | 所屬使用者的使用者名稱:使用者頭像為使用它的使用者;客戶端上傳的為上傳者;你的服務端上傳時可以用 owner 指定。沒有或已被刪除為 null |
group_id | String | 群檔案所在的群 ID,其他為 null |
via | String | 上傳方式:client 客戶端 / openapi 服務端 / console 控制檯 |
created_at | String | 建立上傳的時間,保留期從這時算起 |
expires_at | String | 過期時間:訊息附件和設定了保留天數的群檔案按應用當前的保留天數算出,修改保留天數後隨之變化;其他為 null |
in_use | Boolean | 頭像是否正在被使用者、群或聊天室的資料使用;其他用途為 false |
sha256 | String | 儲存的內容的 SHA-256(十六進位制),只有圖片型別的訊息附件、群檔案和頭像有,其他為 null |
created_by | String | 上傳者的標識:透過 OpenAPI 上傳的為所用 Client Secret 的內部 ID,控制檯上傳的為控制檯賬號的 ID,客戶端上傳的為 null |
blocked_at | String | 被遮蔽的時間,沒有被遮蔽為 null |
blocked_by | String | 遮蔽方:system 系統(內容安全自動遮蔽,或按稽核人員的結論遮蔽) / platform 平臺,沒有被遮蔽為 null |
block_rule_source | String | 遮蔽依據的規則:platform 平臺的規則 / tenant 你的應用的規則,沒有被遮蔽為 null |
block_reason | String | 遮蔽的原因,沒有被遮蔽為 null |
deleted_at | String | 刪除時間,沒有刪除為 null |
delete_reason | String | 刪除原因,見下表,沒有刪除為 null |
delete_reason 的取值:
| 取值 | 說明 |
|---|---|
expired | 訊息附件或群檔案超過了保留天數 |
deleted | 被你的服務端或控制檯刪除,或在客戶端刪除了群檔案 |
unused | 頭像上傳後 24 小時內沒有被使用 |
released | 頭像被替換 7 天后,或聊天室解散 7 天后的封面 |
user_deleted | 所屬使用者被刪除 |
group_dismissed | 群已解散 |
upload_failed | 完成上傳時檢查不透過,如格式不符合型別 |
canceled | 上傳被取消 |
upload_expired | 上傳到期仍未完成 |
evidence_expired | 被遮蔽的檔案保留期滿 |
一張剛完成上傳的圖片附件:
{
"file_id": "99606093402996736",
"purpose": "attachment",
"kind": "image",
"status": "active",
"url": "https://im.example.com/media/v1/f/99606093402996736/DC0neNm6HBbxGW9bN6g_iA",
"thumbnail_url": "https://im.example.com/media/v1/f/99606093402996736/DC0neNm6HBbxGW9bN6g_iA/thumb",
"name": "photo.jpg",
"content_type": "image/jpeg",
"size": 269803,
"width": 1080,
"height": 720,
"owner": null,
"group_id": null,
"via": "openapi",
"created_at": "2026-10-02T20:39:03.259Z",
"expires_at": "2026-11-01T20:39:03.259Z",
"in_use": false,
"sha256": "6c458b05f583eca6c08cd7296ec4d2811c68cf59cbc3c8b30feeb8cdc45994ef",
"created_by": "99604957107322880",
"blocked_at": null,
"blocked_by": null,
"block_rule_source": null,
"block_reason": null,
"deleted_at": null,
"delete_reason": null
}