全部產品
Search
文件中心

Simple Log Service:使用WebTracking採集前端日誌

更新時間:Oct 30, 2025

當需要收集和分析使用者在瀏覽器中的行為資料(如頁面瀏覽、購買記錄、停留時間長度等)時,可以使用 WebTracking 功能,只需對業務代碼進行少量改動,即可將使用者行為資訊上傳至Log Service,用於後續的行為分析與業務最佳化。

目前,WebTracking 支援以下兩種接入方案,推薦優先採用STS安全直傳模式:

  • STS 安全直傳模式(推薦)
    前端通過企業後端擷取阿里雲 STS 頒發的臨時安全性權杖(含臨時 AccessKey、SecurityToken 和受限權限原則),並使用該令牌向 SLS 發起帶簽名的日誌寫入請求。憑證具備時效性和最小許可權,可有效防範因前端配置泄露導致的日誌偽造或資料汙染,適用於生產環境。

  • 匿名直傳模式
    前端直接通過公開的 WebTracking Endpoint 寫入日誌,無需身份憑證,配置簡單、接入快速。但需開啟 Logstore 的匿名寫入許可權,一旦 Project 或 Logstore 資訊泄露,可能被惡意利用,存在資料汙染風險,僅建議用於測試環境。

準備雲資源

開始採集日誌前,需先建立用於儲存和管理日誌的基礎資源。

步驟一:建立Project

Project 是Log Service的資源嵌入式管理單元,用於隔離不同業務。

操作路徑:登入Log Service控制台,單擊建立Project

配置項:

  • 所屬地區:根據日誌來源選擇,建立後不可修改。

  • Project名稱:阿里雲內全域唯一,建立後不可修改。

  • 其他配置保持預設,單擊建立

步驟二:建立Logstore

Logstore 是日誌的儲存單元,所有前端日誌都將寫入此處。

操作路徑: 進入目標 Project,在左側導覽列,選擇日誌儲存image, 單擊 +。

配置項:

  • Logstore名稱:在Project內唯一,建立後不可修改,如 web-tracking-logstore

  • Logstore類型:根據規格對比選擇標準型或查詢型。

  • 計費模式

    • 按使用功能計費:適合日誌量小或開發測試的情境。

    • 按寫入資料量計費:適合日誌量穩定且需要長期分析的情境。

  • 資料儲存時間:預設為30天(支援1~3650 天)。

  • 其他配置保持預設,單擊確定

STS 安全直傳模式(推薦)

此方案通過引入後端憑證服務解決前端密鑰安全問題,是生產環境部署的推薦方案。

工作原理

前端應用不儲存長期密鑰,而是向您所部署的STS服務(可部署在商務服務器上)請求籤發臨時安全憑證。WebTracking SDK 使用該憑證上傳日誌,憑證預設有效期間為60分鐘,到期自動失效,安全可控。

  1. 用戶端請求憑證:前端應用向商務服務器發起請求,申請用於上傳日誌的臨時訪問憑證。

  2. 伺服器驗證並擷取臨時憑證:商務服務器驗證請求合法性後,使用預配置的RAM使用者身份,調用阿里雲STS的AssumeRole介面,申請扮演一個具備SLS寫入許可權的RAM角色。

  3. STS簽發臨時憑證:STS驗證角色許可權後,產生包含AccessKey ID、AccessKey Secret和STS Token等資訊的臨時憑證。

  4. 伺服器下發憑證:商務服務器將臨時憑證返回給前端應用。

  5. 用戶端上傳日誌:用戶端使用該臨時憑證,通過WebTracking SDK將採集到的日誌上傳至指定Logstore。

步驟一:配置RAM許可權體系

此步驟為後端憑證服務和前端SDK分別建立安全的身份和許可權,遵循許可權最小化原則。

1. 建立供前端應用扮演的RAM角色

此角色是一個沒有長期密鑰的虛擬身份,專門用於被臨時扮演以擷取日誌寫入許可權。

1.1 建立RAM角色

操作路徑: 登入RAM控制台,在左側導覽列,選擇身份管理 > 角色,單擊建立角色

配置說明:

  • 信任主體類型:選擇雲帳號

  • 信任主體名稱:選擇當前雲帳號或指定其他雲帳號。

  • 單擊確定,輸入角色名稱sls-web-tracking

1.2 建立僅允許寫入日誌的權限原則

此策略精確地限制了上述角色只能向指定的 Logstore 寫入日誌。

操作路徑:在左側導覽列,選擇許可權管理 > 權限原則,單擊建立權限原則

配置說明:

  • 使用指令碼編輯模式,粘貼以下指令碼,並將<Project名稱><Logstore名稱>替換為實際的Project、Logstore名稱。

    {
      "Version":"1",
      "Statement":[
        {
          "Effect":"Allow",
          "Action":[
            "log:PostLogStoreLogs",
            "log:PutLogs"
          ],
          "Resource":[
            "acs:log:*:*:project/<Project名稱>/logstore/<Logstore名稱>"
          ]
        }
      ]
    }
  • 單擊確定,輸入策略名稱稱post-logs-policy,完成建立。

1.3 為RAM角色授予日誌寫入許可權

將上一步建立的寫入許可權賦予前端扮演的角色。

操作路徑:在左側導覽列,選擇身份管理 > 角色,單擊目標角色名稱,進入角色詳情頁,在許可權管理模組單擊新增授權

配置說明:

  • 新增授權面板中,搜尋並選中上一步建立的自訂權限原則(sls-logstore-write-policy)。

  • 單擊確認授權,完成許可權綁定。

2. 建立供後端服務使用的RAM使用者

此使用者擁有一個長期 AccessKey,用於向 STS 服務發起扮演角色的請求。

2.1 建立RAM使用者

操作路徑:  登入RAM控制台,在左側導覽列,選擇身份管理 > 使用者,單擊建立使用者

配置說明:

  • 登入名稱稱:僅支援英文字母、數字、半形句號(.)、短劃線(-)和底線(_),最多64個字元,如:sls-token-service

  • 訪問方式:勾選使用永久 AccessKey 訪問

  • 其餘配置保持預設,單擊確定,完成建立,並儲存 AccessKey ID 和 AccessKey Secret資訊。

    AccessKey Secret 僅在建立時顯示一次,不支援後續查詢,請務必立即儲存至安全位元置。
2.2 為RAM使用者授予角色扮演的許可權

操作路徑:單擊目標使用者名稱稱,進入使用者詳情頁,切換到許可權管理頁簽,單擊新增授權

配置說明:

  • 權限原則模組,勾選AliyunSTSAssumeRoleAccess策略。

  • 其餘配置保持預設,單擊確認新增授權,完成許可權綁定。

小結:後端服務使用 RAM 使用者(AK/SK)扮演 sls-web-tracking 角色,產生臨時安全憑證返回給前端應用,WebTracking SDK 使用臨時憑證安全上傳日誌。

步驟二:搭建後端STS臨時憑證服務

需搭建一個後端介面,用於接收前端的憑證請求,並安全地返回 STS 臨時憑證,以下以Python + Flask 為例。

您可根據實際技術棧參考附錄一:多語言STS樣本,選擇 Java、Node.js等其他語言實現。

1. 準備伺服器環境

在實際部署時,您可以將調用STS服務的介面整合到自己的商務服務器中,而無需單獨準備伺服器,也可以將介面單獨部署,只需確保該伺服器滿足如下要求:

  • 前端應用可通過 HTTP(S) 訪問該伺服器。

  • 安裝Python3環境,推薦Python3.8及以上版本。

執行如下命令,安裝調用阿里雲STS服務介面所需的依賴庫。

# 安裝 Flask Web 架構及阿里雲 SDK 相關的依賴庫
pip3 install Flask==3.1.2
pip3 install aiohttp==3.8.4
pip3 install alibabacloud-credentials==0.3.2
pip3 install alibabacloud-sts20150401==1.1.3
pip3 install alibabacloud-tea==0.3.2
pip3 install alibabacloud-tea-openapi==0.3.7
pip3 install alibabacloud-tea-util==0.3.8
pip3 install alibabacloud-tea-xml==0.0.2

2. 編寫後端STS服務代碼

建立一個HTTP介面 /get_sts_token,用於產生並返回STS臨時憑證。

2.1 建立專案目錄與檔案
# 建立並進入專案目錄
mkdir my_web_sample
cd my_web_sample
touch main.py
2.2 編輯main.py檔案

請將以下代碼粘貼至 main.py 檔案,並將 <YOUR_ROLE_ARN> 替換為RAM 角色 sls-web-tracking 對應的 ARN, <YOUR_ROLE_SESSION_NAME> 替換為自訂的會話名稱(例如role_session_test)。

import json
from flask import Flask, render_template
from alibabacloud_tea_openapi.models import Config
from alibabacloud_sts20150401.client import Client as Sts20150401Client
from alibabacloud_sts20150401 import models as sts_20150401_models
from alibabacloud_credentials.client import Client as CredentialClient

app = Flask(__name__)

# ================== 使用者配置區 ==================
# 替換為您的 RAM 角色 ARN,格式:acs:ram::${accountId}:role/${roleName}
role_arn_for_sls_upload = '<YOUR_ROLE_ARN>'

# 設定角色會話名稱(建議唯一標識請求來源)
role_session_name = '<YOUR_ROLE_SESSION_NAME>'  # 如:sls-web-session-001

# STS服務所在地區,例如cn-hangzhou。
region_id = 'cn-hangzhou'
# ==============================================

@app.route("/")
def hello_world():
    return render_template('index.html')

@app.route('/get_sts_token', methods=['GET'])
def get_sts_token():
    """
    介面:/get_sts_token
    方法:GET
    功能:調用 STS AssumeRole 介面擷取臨時安全性權杖
    返回:JSON 格式的 Credentials 對象
    """
    # 初始化 CredentialClient 時不指定參數,代表使用預設憑據鏈。
    # 在本地運行程式時,可以通過環境變數 ALIBABA_CLOUD_ACCESS_KEY_ID、ALIBABA_CLOUD_ACCESS_KEY_SECRET 指定 AK;
    # 在 ECS\ECI\Container Service上運行時,可以通過環境變數 ALIBABA_CLOUD_ECS_METADATA 來指定綁定的執行個體節點角色,SDK 會自動換取 STS 臨時憑證。
    config = Config(
        region_id=region_id,
        credential=CredentialClient()
    )
    sts_client = Sts20150401Client(config=config)

    # 構造 AssumeRole 請求
    assume_role_request = sts_20150401_models.AssumeRoleRequest(
        role_arn=role_arn_for_sls_upload,
        role_session_name=role_session_name,
    )
      
    # 調用 STS 擷取臨時憑證
    response = sts_client.assume_role(assume_role_request)
    
    token = json.dumps(response.body.credentials.to_map())
    return token


app.run(host="0.0.0.0", port=80)

3. 啟動後端服務

執行如下命令,使用步驟一中建立的RAM使用者的存取金鑰啟動服務:

ALIBABA_CLOUD_ACCESS_KEY_ID=<YOUR_AK_ID> 
ALIBABA_CLOUD_ACCESS_KEY_SECRET=<YOUR_AK_SECRET> 
python3 main.py

4. 驗證介面是否正常工作

發送測試請求:

curl http://<伺服器公網IP地址>/get_sts_token

成功響應樣本:

{
  "AccessKeyId": "STS.L4xxxxxx",
  "AccessKeySecret": "Dcyyyyyyyy",
  "Expiration": "2025-04-05T10:30:00Z",
  "SecurityToken": "CAISzxxxxxxxxxxx..."
}

驗證要點:

  • 返回欄位包含 AccessKeyIdAccessKeySecretSecurityToken

  • AccessKeyId 以 STS. 開頭,表示是臨時憑證。

  • Expiration 表示到期時間,應在合理範圍內。

步驟三:前端整合WebTracking SDK

在前端應用(瀏覽器或小程式)中整合 SDK,並配置 STS 外掛程式以實現安全授權和日誌上報。完整樣本工程請參見附錄二:前端應用樣本工程

1. 安裝SDK依賴

使用 npm 安裝 WebTracking SDK 及其 STS 外掛程式:

npm install --save @aliyun-sls/web-track-browser
npm install --save @aliyun-sls/web-sts-plugin

2. 初始化 SDK 並配置 STS 身分識別驗證

在前端專案中建立一個用於初始化日誌採集器的 JavaScript 檔案,例如index.js。該檔案負責初始化 SlsTracker 執行個體,配置 STS 臨時憑證外掛程式。

2.1 引入核心模組
import SlsTracker from "@aliyun-sls/web-track-browser";
import createStsPlugin from "@aliyun-sls/web-sts-plugin";
2.2 配置Log Service基礎資訊

請根據您的實際資源資訊填寫以下參數:

const opts = {
  host: "${endpoint}", // 所在地區的服務入口。例如cn-hangzhou.log.aliyuncs.com
  project: "${project}", // Project 名稱
  logstore: "${logstore}", // Logstore 名稱
  time: 10, // 發送日誌的時間間隔,預設是10秒
  count: 10, // 發送日誌的數量大小,預設是10條
  topic: "topic", // 自訂日誌主題
  source: "source",
  tags: {
    tags: "tags",
  },
};
2.3 配置STS外掛程式以實現安全授權

為保障安全性,前端應用不應持有長期 AccessKey。推薦通過後端服務擷取臨時安全性權杖(STS Token),並通過外掛程式動態重新整理。

const stsOpt = {
  accessKeyId: "",
  accessKeySecret: "",
  securityToken: "",
  
  // 重新整理 STS Token 的非同步函數
  refreshSTSToken: () =>
    new Promise((resolve, reject) => {
      const xhr = new window.XMLHttpRequest();
      xhr.open("GET", "http://<ECS執行個體公網IP地址>/get_sts_token", true);
      xhr.send();
      
      xhr.onreadystatechange = () => {
        if (xhr.readyState === 4) {
          if (xhr.status === 200) {
            let credential = JSON.parse(xhr.response);
            // 更新臨時憑證
            stsOpt.accessKeyId = credential.AccessKeyId;
            stsOpt.accessKeySecret = credential.AccessKeySecret;
            stsOpt.securityToken = credential.SecurityToken;
            resolve();
          } else {
            reject("Wrong status code.");
          }
        }
      };
    }),
   // (可選)自訂重新整理頻率,預設 5 分鐘(300000ms)
  // refreshSTSTokenInterval: 300000,
  
  // (可選)設定 token 到期前多久提前重新整理(單位毫秒)
  // stsTokenFreshTime: undefined,
};
2.4 初始化Tracker執行個體並啟用STS外掛程式
// 建立 tracker 執行個體
const tracker = new SlsTracker(opts);

// 建立並註冊 sts 外掛程式
const stsPlugin = createStsPlugin(stsOpt);
tracker.useStsPlugin(stsPlugin);

3. 在業務代碼中上報日誌

在 Web 頁面,通過標準 DOM 事件綁定機制捕獲使用者行為,並調用 tracker.send() 方法發送自訂日誌。

3.1 監聽使用者互動事件

樣本:記錄使用者登入行為

document.getElementById("loginButton").addEventListener("click", () => {
  const username = document.getElementById("username").value;
  
  tracker.send({
    eventType: "login",
    username: username,
  });
  
  console.log("Login event tracked for:", username);
});
3.2 在HTML中引用指令碼

確保 JavaScript 檔案被正確載入。建議使用模組化方式匯入:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>使用者行為監控樣本</title>
</head>
<body>
  <input type="text" id="username" placeholder="請輸入使用者名稱" />
  <button id="loginButton">登入</button>

  <!-- 使用模組化指令碼 -->
  <script type="module" src="/static/js/index.js"></script>
</body>
</html>

4. 運行並測試應用

啟動並訪問前端頁面,觸發使用者行為事件,使 WebTracking SDK 開始採集日誌並上傳。

  1. 啟動前端服務,訪問前端頁面:http://<伺服器公網IP>

  2. 類比使用者操作(點擊登入按鈕)。

  3. 開啟瀏覽器開發人員工具(F12):

    • 查看 Console 輸出是否顯示Login event tracked for: xxx 。

    • 在 Network 面板檢查是否有成功發送到 cn-xxx.log.aliyuncs.com 的 POST 請求。

5. 驗證日誌上報

確認前端日誌已通過安全鏈路成功寫入阿里雲Log Service的Logstore。

  1. 登入Log Service控制台

  2. 在Project列表中,單擊目標Project。

  3. 進入日誌庫頁面,單擊目標Logstore名稱前的image展開目標Logstore。

  4. 單擊image,進入查詢/分析頁面。

  5. 單擊開啟索引,在右側彈窗中單擊自動產生索引

  6. 系統將自動識別日誌結構並產生推薦欄位配置,確認無誤後單擊確定

  7. 開啟索引後,建議等待約1分鐘以確保索引生效,之後即可進行日誌查詢。

匿名直傳模式

本方案通過開啟WebTracking開關,開放Logstore的公網寫入許可權,允許前端直接通過SDK、HTTP請求等方式匿名上報日誌。

重要

開啟WebTracking開關後,日誌上傳無需身分識別驗證,一旦 Project 或 Logstore 資訊泄露,可能被惡意利用,存在資料汙染風險,建議僅在測試環境使用。

步驟一:開啟WebTracking開關

  1. 登入Log Service控制台

  2. 在Project列表地區,單擊目標Project。

  3. 日誌儲存 > 日誌庫頁簽中,選擇目標Logstore右側的表徵圖 > 修改

  4. Logstore屬性頁面,單擊修改

  5. 開啟WebTracking開關,單擊儲存

步驟二:配置匿名採集並上報日誌

支援如下四種接入方式:

  • 整合WebTracking SDK:在前端代碼中引入WebTracking SDK,調用 send() 方法發送結構化日誌。適用於現代 Web 和小程式應用。

  • HTTP GET請求:將日誌資料拼接在 URL 參數中,通過 GET 請求直接上報。實現簡單,適合調試或少量日誌的輕量採集。

  • HTML標籤(img):使用 <img> 標籤的 src 屬性發起請求,日誌資訊編碼在 URL 中。無需 JavaScript,天然支援跨域,適用於靜態頁面或郵件追蹤等無 JS 環境。

  • OpenAPI批量寫入:通過 POST 請求調用 SLS OpenAPI,適合服務端集中上報大量資料。

WebTracking SDK

在匿名寫入模式下,無需配置 STS 外掛程式,直接初始化 SDK 即可。

安裝依賴

# 瀏覽器端
npm install --save @aliyun-sls/web-track-browser

# 小程式端
npm install --save @aliyun-sls/web-track-mini

配置Log Service基本資料

import SlsTracker from '@aliyun-sls/web-track-browser'

const opts = {
  host: '${host}', // 所在地區的服務入口。例如cn-hangzhou.log.aliyuncs.com
  project: '${project}', // Project名稱。
  logstore: '${logstore}', // Logstore名稱。
  time: 10, // 發送日誌的時間間隔,預設是10秒。
  count: 10, // 發送日誌的數量大小,預設是10條。
  topic: 'topic',// 自訂日誌主題。
  source: 'source',
  tags: {
    tags: 'tags',
  },
}

const tracker = new SlsTracker(opts)  // 建立SlsTracker對象

上報日誌

上傳單條日誌時,每條日誌單獨作為一個對象Object。上傳多條日誌時,資料結構是包含多個對象Object的數組Array

單條日誌上傳

tracker.send({
  eventType:'view_product',
  productName: 'Tablet',
  price: 500
})

單條日誌立即上傳(time和count參數不生效)

tracker.sendImmediate({
  eventType:'view_product',
  productName: 'Tablet',
  price: 500
})

批量日誌上傳

tracker.sendBatchLogs([
  {
    eventType: 'view_product',
    productName: 'Tablet',
    price: 500
  },
  {
    eventType: 'view_product',
    productName: 'Laptop',
    price: 1200
  }
])

批量日誌立即上傳(time和count參數不生效)

tracker.sendBatchLogsImmediate([
  {
    eventType:'view_product',
    productName: 'Tablet',
    price: 500
  },
  {
    eventType:'view_product',
    productName: 'Laptop',
    price: 1200
  }
])

HTTP GET請求

將日誌資料作為URL參數,通過GET 請求直接發送至Log Service接收端點。

curl --request GET 'https://${project}.${host}/logstores/${logstore}/track?APIVersion=0.6.0&key1=val1&key2=val2'
  • host:Log Service所在地區的Endpoint。更多資訊,請參見服務入口

  • key1=val1&key2=val2:上傳到Log Service的欄位名稱和欄位值(Key-Value),支援設定多個欄位,長度必須小於16 KB。

HTML標籤(img)

通過在前端頁面中嵌入一個不可見的 <img> 標籤,利用瀏覽器自動載入圖片的機制觸發日誌上報。

<!-- 採集自訂欄位 -->
<img src='https://${project}.${host}/logstores/${logstore}/track.gif?APIVersion=0.6.0&key1=val1&key2=val2'/>
<!-- 額外採集User-Agent和Referer -->
<img src='https://${project}.${host}/logstores/${logstore}/track_ua.gif?APIVersion=0.6.0&key1=val1&key2=val2'/>
說明

使用track_ua.gif會自動採集User-Agent和Referer資訊。為避免瀏覽器緩衝,建議加入時間戳記參數。

OpenAPI:批量寫入日誌

當需要上報大量日誌時,可通過調用PutWebtracking - 通過WebTracking批量寫入日誌介面上傳多條日誌。

步驟三:驗證日誌上報

確認前端日誌已成功寫入阿里雲Log Service的Logstore。

  1. 登入Log Service控制台

  2. 在Project列表中,單擊目標Project。

  3. 進入日誌庫頁面,單擊目標Logstore名稱前的image展開目標Logstore。

  4. 單擊image,進入查詢/分析頁面。

  5. 單擊開啟索引,在右側彈窗中單擊自動產生索引

  6. 系統將自動識別日誌結構並產生推薦欄位配置,確認無誤後單擊確定

  7. 開啟索引後,建議等待約1分鐘以確保索引生效,之後即可進行日誌查詢。

配額與限制

為保障服務穩定性,SLS WebTracking 在瀏覽器端對日誌上報設定了合理的配額限制:

  • 單次請求最巨量資料量:3 MB

  • 單次請求最多日誌條數:4,096 條

計費說明

使用WebTracking 採集前端日誌時,WebTracking 功能本身不收取額外費用,但由此產生的日誌寫入、儲存與查詢等操作可能會產生如下計費。

1. 計費模式選擇

在建立 Logstore 時可選擇不同的計費方式:

  • 按寫入資料量計費:適合需要對日誌進行長期儲存、分析加工及多情境消費的複合型使用情境。

  • 按使用功能計費:適合需靈活控製成本的輕量級或階段性使用情境。

2. 核心計費項目

按寫入資料量計費

  • 原始寫入資料量:主要費用來源,根據上傳的未壓縮原始日誌大小(GB)計費。此費用已包含資料寫入、索引、API 呼叫及首月(30天)熱儲存。

  • 儲存費用:日誌儲存超過30天后,會額外收取儲存費。

按使用功能計費

  • 索引流量:資料寫入時,按未壓縮的原始日誌大小收取的一次性費用,是日誌可查詢的前提。

  • 儲存費用:從第一天開始,按壓縮後的實際佔用空間計費。

  • 讀寫流量讀寫次數活躍Shard租用等。

常見問題

是否可以通過 CDN 方式引入 WebTracking SDK?

支援,適用於無法使用 npm 構建流程的輕量級前端專案、靜態頁面或快速驗證情境。

版本滯後風險:當前 CDN 託管的最高版本為 0.3.5,功能可能落後於 npm 發布的最新版本

引入方式:

  1. 在 HTML 檔案的 <head> 或 <body> 標籤中添加以下指令碼引用。

    <script src="https://g.alicdn.com/sls/sls-js-sdk/0.3.5/web-track-browser.js"></script>
  2. SDK 載入完成後,可通過全域對象 window.SLS_Tracker 初始化 tracker 執行個體:

    if (window.SLS_Tracker) {
      const tracker = new SLS_Tracker({
        host: 'your-project.cn-hangzhou.log.aliyuncs.com',
        project: 'your-project',
        logstore: 'your-logstore',
        time: 10,
        count: 10
      });
    }
    

相關文檔

附錄一:多語言STS樣本

為方便不同技術棧的開發人員快速搭建後端 STS 憑證服務,阿里雲提供多種語言的開源樣本程式,支援 Java、Node.js、PHP、Ruby 等主流語言。這些樣本基於AssumeRole介面實現,用於向前端應用安全簽發臨時存取權杖。

樣本專案地址:Java、Node.js、PHP、Ruby

使用說明:修改專案中的 config.json 設定檔,並根據對應語言的說明啟動服務。

語言

連接埠

Java

7080

Node.js

3000

PHP

8000

Ruby

4567

附錄二:前端應用樣本工程

瀏覽器端:simple-web-tracking-sts.zip