什麼是Mux Node API Library?
Mux Node API Library是一個用於與Mux服務進行交互的JavaScript/TypeScript庫,允許開發者通過編程方式創建、管理視頻資產和直播流等多媒體內容。如何使用Mux Node API Library?
使用該庫需要先安裝它,然後通過提供Mux的API密鑰來初始化客戶端實例。之後可以調用各種方法來操作視頻資產、直播流等。適用場景
適用於需要在後端處理視頻上傳、播放控制、即時流管理和分析的Web應用或服務。主要功能
優勢與侷限性
如何使用
使用案例
常見問題
相關資源
🚀 Mux Node API 庫
本庫為從服務器端 TypeScript 或 JavaScript 訪問 Mux REST API 提供了便捷途徑。
⚠️ 重要提示
2024 年 2 月,此 SDK 更新至 8.0 版本。如需升級到 8.x 版本,請參閱 UPGRADE_8.x.md
REST API 文檔可在 docs.mux.com 上找到。本庫的完整 API 文檔可在 api.md 中查看。
🚀 快速開始
此庫為從服務器端 TypeScript 或 JavaScript 訪問 Mux REST API 提供了便捷途徑。可參考以下的安裝和使用示例快速上手。
✨ 主要特性
- 提供便捷的 REST API 訪問方式。
- 包含 TypeScript 定義,方便類型檢查。
- 提供 JWT 助手函數,簡化 JWT 操作。
- 支持自動重試和超時設置。
- 支持分頁操作。
- 可訪問原始響應數據。
- 支持自定義請求。
- 可自定義 fetch 客戶端。
- 支持日誌記錄和中間件。
- 可配置 HTTP(S) 代理。
📦 安裝指南
使用以下命令安裝 Mux Node API 庫:
npm install @mux/mux-node
💻 使用示例
基礎用法
import Mux from '@mux/mux-node';
const client = new Mux({
tokenId: process.env['MUX_TOKEN_ID'], // 這是默認值,可以省略
tokenSecret: process.env['MUX_TOKEN_SECRET'], // 這是默認值,可以省略
});
const asset = await client.video.assets.create({
inputs: [{ url: 'https://storage.googleapis.com/muxdemofiles/mux-video-intro.mp4' }],
playback_policies: ['public'],
});
console.log(asset.id);
高級用法
請求和響應類型
本庫包含所有請求參數和響應字段的 TypeScript 定義。你可以像這樣導入和使用它們:
import Mux from '@mux/mux-node';
const client = new Mux({
tokenId: process.env['MUX_TOKEN_ID'], // 這是默認值,可以省略
tokenSecret: process.env['MUX_TOKEN_SECRET'], // 這是默認值,可以省略
});
const params: Mux.Video.AssetCreateParams = {
inputs: [{ url: 'https://storage.googleapis.com/muxdemofiles/mux-video-intro.mp4' }],
playback_policies: ['public'],
};
const asset: Mux.Video.Asset = await client.video.assets.create(params);
每個方法、請求參數和響應字段的文檔都在文檔字符串中提供,並且在大多數現代編輯器中懸停時會顯示。
📚 詳細文檔
JWT 助手 (API 參考)
你可以使用任何與 JWT 兼容的庫,但我們在 SDK 中包含了一些輕量級助手,以便更輕鬆地開始使用。
// 假設你已在環境變量中指定了簽名密鑰:
// 簽名令牌 ID:process.env.MUX_SIGNING_KEY
// 簽名令牌密鑰:process.env.MUX_PRIVATE_KEY
// 最簡單的請求,默認為視頻類型,有效期為 7 天。
const token = mux.jwt.signPlaybackId('some-playback-id');
// https://stream.mux.com/some-playback-id.m3u8?token=${token}
// 如果你想簽署縮略圖
const thumbParams = { time: 14, width: 100 };
const thumbToken = mux.jwt.signPlaybackId('some-playback-id', {
type: 'thumbnail',
params: thumbParams,
});
// https://image.mux.com/some-playback-id/thumbnail.jpg?token=${token}
// 如果你想簽署 gif
const gifToken = mux.jwt.signPlaybackId('some-playback-id', { type: 'gif' });
// https://image.mux.com/some-playback-id/animated.gif?token=${token}
// 以下是故事板的示例
const storyboardToken = mux.jwt.signPlaybackId('some-playback-id', {
type: 'storyboard',
});
// https://image.mux.com/some-playback-id/storyboard.jpg?token=${token}
// 你還可以使用 `signViewerCounts` 來獲取用於請求 Mux 參與計數 API 的令牌
// https://docs.mux.com/guides/see-how-many-people-are-watching
const statsToken = mux.jwt.signViewerCounts('some-live-stream-id', {
type: 'live_stream',
});
// https://stats.mux.com/counts?token={statsToken}
一次簽署多個 JWT
在需要多個令牌的情況下,例如使用 Mux Player 時,事情可能會很快變得繁瑣。例如:
const playbackToken = await mux.jwt.signPlaybackId(id, {
expiration: "1d",
type: "playback"
})
const thumbnailToken = await mux.jwt.signPlaybackId(id, {
expiration: "1d",
type: "thumbnail",
})
const storyboardToken = await mux.jwt.signPlaybackId(id, {
expiration: "1d",
type: "storyboard"
})
const drmToken = await mux.jwt.signPlaybackId(id, {
expiration: "1d",
type: "drm_license"
})
<mux-player
playback-token={playbackToken}
thumbanil-token={thumbnailToken}
storyboard-token={storyboardToken}
drm-token={drmToken}
playbackId={id}
></mux-player>
為簡化此用例,你可以向 signPlaybackId
提供多個類型以獲取多個令牌。這些令牌以 Mux Player 可以作為屬性使用的格式提供:
// { "playback-token", "thumbnail-token", "storyboard-token", "drm-token" }
const tokens = await mux.jwt.signPlaybackId(id, {
expiration: "1d",
type: ["playback", "thumbnail", "storyboard", "drm_license"]
})
<mux-player
{...tokens}
playbackId={id}
></mux-player>
如果你想為單個令牌提供參數(例如,如果你想設置縮略圖的 time
),可以提供 [type, typeParams]
而不是 type
:
const tokens = await mux.jwt.signPlaybackId(id, {
expiration: "1d",
type: ["playback", ["thumbnail", { time: 2 }], "storyboard", "drm_license"]
})
解析 Webhook 有效負載
為驗證給定的有效負載是否由 Mux 發送,並解析 Webhook 有效負載以在你的應用程序中使用,你可以使用 mux.webhooks.unwrap
實用方法。
此方法接受原始 body
字符串和標頭列表。只要你在實例化庫時在適當的配置屬性中設置了 webhookSecret
,所有 Webhook 都將自動驗證其真實性。
以下示例展示瞭如何使用 Next.js 應用目錄 API 路由處理 Webhook:
// app/api/mux/webhooks/route.ts
import { revalidatePath } from 'next/cache';
import { headers } from 'next/headers';
import Mux from '@mux/mux-node';
const mux = new Mux({
webhookSecret: process.env.MUX_WEBHOOK_SECRET,
});
export async function POST(request: Request) {
const headersList = headers();
const body = await request.text();
const event = mux.webhooks.unwrap(body, headersList);
switch (event.type) {
case 'video.live_stream.active':
case 'video.live_stream.idle':
case 'video.live_stream.disabled':
/**
* `event` 現在被理解為以下類型之一:
*
* | Mux.Webhooks.VideoLiveStreamActiveWebhookEvent
* | Mux.Webhooks.VideoLiveStreamIdleWebhookEvent
* | Mux.Webhooks.VideoLiveStreamDisabledWebhookEvent
*/
if (event.data.id === 'MySpecialTVLiveStreamID') {
revalidatePath('/tv');
}
break;
default:
break;
}
return Response.json({ message: 'ok' });
}
驗證 Webhook 簽名
驗證 Webhook 簽名是_可選但建議的_。在我們的 Webhook 安全指南 中瞭解更多信息。
/*
如果標頭有效,此函數不會拋出錯誤,也不會返回值。
如果標頭無效,此函數將拋出以下錯誤之一:
- new Error(
"The webhook secret must either be set using the env var, MUX_WEBHOOK_SECRET, on the client class, Mux({ webhookSecret: '123' }), or passed to this function",
);
- new Error('Could not find a mux-signature header');
- new Error(
'Webhook body must be passed as the raw JSON string sent from the server (do not parse it first).',
);
- new Error('Unable to extract timestamp and signatures from header')
- new Error('No v1 signatures found');
- new Error('No signatures found matching the expected signature for payload.')
- new Error('Webhook timestamp is too old')
*/
/*
`body` 是原始請求體。它應該是 JSON 對象的字符串表示形式。
`headers` 是 request.headers 中的值
`secret` 是此配置的 Webhook 的簽名密鑰。你可以在 Webhook 儀表板中找到它
(請注意,此密鑰與你的 API 密鑰不同)
*/
mux.webhooks.verifySignature(body, headers, secret);
請注意,在傳入有效負載(body)時,你要傳入原始未解析的請求體,而不是解析後的 JSON。如果你使用的是 express,以下是一個示例:
const Mux = require('@mux/mux-node');
const mux = new Mux();
const express = require('express');
const bodyParser = require('body-parser');
/**
* 你需要確保這在外部是可訪問的。ngrok (https://ngrok.com/)
* 讓這變得非常容易。
*/
const webhookSecret = process.env.WEBHOOK_SECRET;
const app = express();
app.post('/webhooks', bodyParser.raw({ type: 'application/json' }), async (req, res) => {
try {
// 如果簽名無效,將拋出異常
const isValidSignature = mux.webhooks.verifySignature(req.body, req.headers, webhookSecret);
console.log('Success:', isValidSignature);
// 將原始的 req.body 轉換為 JSON,它最初是 Buffer (原始)
const jsonFormattedBody = JSON.parse(req.body);
// await doSomething();
res.json({ received: true });
} catch (err) {
// 出錯時,返回錯誤消息
return res.status(400).send(`Webhook Error: ${err.message}`);
}
});
app.listen(3000, () => {
console.log('Example app listening on port 3000!');
});
錯誤處理
當庫無法連接到 API 時,或者如果 API 返回非成功狀態碼(即 4xx 或 5xx 響應),將拋出 APIError
的子類:
const liveStream = await client.video.liveStreams
.create({ playback_policies: ['public'] })
.catch(async (err) => {
if (err instanceof Mux.APIError) {
console.log(err.status); // 400
console.log(err.name); // BadRequestError
console.log(err.headers); // {server: 'nginx', ...}
} else {
throw err;
}
});
錯誤代碼如下:
狀態碼 | 錯誤類型 |
---|---|
400 | BadRequestError |
401 | AuthenticationError |
403 | PermissionDeniedError |
404 | NotFoundError |
422 | UnprocessableEntityError |
429 | RateLimitError |
>=500 | InternalServerError |
N/A | APIConnectionError |
重試
某些錯誤默認會自動重試 2 次,並採用短指數退避策略。連接錯誤(例如,由於網絡連接問題)、408 請求超時、409 衝突、429 速率限制和 >=500 內部錯誤默認都會重試。
你可以使用 maxRetries
選項來配置或禁用此功能:
// 為所有請求配置默認值:
const client = new Mux({
maxRetries: 0, // 默認值為 2
});
// 或者,為每個請求配置:
await client.video.assets.retrieve('t02rm...', {
maxRetries: 5,
});
超時
請求默認在 1 分鐘後超時。你可以使用 timeout
選項進行配置:
// 為所有請求配置默認值:
const client = new Mux({
timeout: 20 * 1000, // 20 秒(默認值為 1 分鐘)
});
// 為每個請求覆蓋:
await client.video.assets.retrieve('t02rm...', {
timeout: 5 * 1000,
});
超時發生時,將拋出 APIConnectionTimeoutError
。
請注意,超時的請求將默認重試兩次。
自動分頁
Mux API 中的列表方法是分頁的。你可以使用 for await … of
語法遍歷所有頁面的項目:
async function fetchAllDeliveryReports(params) {
const allDeliveryReports = [];
// 根據需要自動獲取更多頁面。
for await (const deliveryReport of client.video.deliveryUsage.list()) {
allDeliveryReports.push(deliveryReport);
}
return allDeliveryReports;
}
或者,你可以一次請求一個頁面:
let page = await client.video.deliveryUsage.list();
for (const deliveryReport of page.data) {
console.log(deliveryReport);
}
// 提供了方便的方法用於手動分頁:
while (page.hasNextPage()) {
page = await page.getNextPage();
// ...
}
高級用法
訪問原始響應數據(例如,標頭)
fetch()
返回的“原始”Response
可以通過所有方法返回的 APIPromise
類型的 .asResponse()
方法訪問。
你還可以使用 .withResponse()
方法獲取原始 Response
以及解析後的數據。
const client = new Mux();
const response = await client.video.assets
.create({
inputs: [{ url: 'https://storage.googleapis.com/muxdemofiles/mux-video-intro.mp4' }],
playback_policies: ['public'],
})
.asResponse();
console.log(response.headers.get('X-My-Header'));
console.log(response.statusText); // 訪問底層的 Response 對象
const { data: asset, response: raw } = await client.video.assets
.create({
inputs: [{ url: 'https://storage.googleapis.com/muxdemofiles/mux-video-intro.mp4' }],
playback_policies: ['public'],
})
.withResponse();
console.log(raw.headers.get('X-My-Header'));
console.log(asset.id);
進行自定義/未記錄的請求
本庫為方便訪問已記錄的 API 進行了類型化。如果你需要訪問未記錄的端點、參數或響應屬性,仍然可以使用該庫。
未記錄的端點
要向未記錄的端點發出請求,你可以使用 client.get
、client.post
和其他 HTTP 動詞。
客戶端上的選項(如重試)在發出這些請求時將被遵守。
await client.post('/some/path', {
body: { some_prop: 'foo' },
query: { some_query_arg: 'bar' },
});
未記錄的參數
要使用未記錄的參數發出請求,你可以在未記錄的參數上使用 // @ts-expect-error
。此庫在運行時不會驗證請求是否與類型匹配,因此你發送的任何額外值都將按原樣發送。
client.foo.create({
foo: 'my_param',
bar: 12,
// @ts-expect-error baz 尚未公開
baz: 'undocumented option',
});
對於使用 GET
動詞的請求,任何額外的參數將在查詢中,所有其他請求將在正文中發送額外的參數。
如果你想顯式發送額外的參數,可以使用 query
、body
和 headers
請求選項。
未記錄的屬性
要訪問未記錄的響應屬性,你可以在響應對象上使用 // @ts-expect-error
訪問響應對象,或將響應對象強制轉換為所需的類型。與請求參數一樣,我們不會驗證或剝離 API 響應中的額外屬性。
自定義 fetch 客戶端
默認情況下,此庫在 Node 中使用 node-fetch
,並期望在其他環境中有全局 fetch
函數。
如果你希望即使在 Node 環境中也使用符合 Web 標準的全局 fetch
函數(例如,如果你使用 --experimental-fetch
運行 Node 或使用 NextJS 並使用 undici
進行填充),在你第一次從 "Mux"
導入之前添加以下導入:
// 告訴 TypeScript 和包使用全局 Web fetch 而不是 node-fetch。
// 注意,儘管名稱如此,但這不會添加任何填充,而是期望在需要時提供它們。
import '@mux/mux-node/shims/web';
import Mux from '@mux/mux-node';
要進行相反的操作,添加 import "@mux/mux-node/shims/node"
(這確實會導入填充)。
如果你在獲取 Response
的錯誤 TypeScript 類型時,這也很有用(更多詳細信息)。
日誌記錄和中間件
你還可以在實例化客戶端時提供自定義的 fetch
函數,該函數可用於在每個請求之前/之後檢查或更改 Request
或 Response
:
import { fetch } from 'undici'; // 作為一個示例
import Mux from '@mux/mux-node';
const client = new Mux({
fetch: async (url: RequestInfo, init?: RequestInit): Promise<Response> => {
console.log('About to make a request', url, init);
const response = await fetch(url, init);
console.log('Got response', response);
return response;
},
});
請注意,如果設置了 DEBUG=true
環境變量,此庫將自動記錄所有請求和響應。
這僅用於調試目的,未來可能會在不通知的情況下更改。
配置 HTTP(S) 代理(例如,用於代理)
默認情況下,此庫對所有 http/https 請求使用穩定的代理,以重用 TCP 連接,消除許多 TCP 和 TLS 握手,併為大多數請求節省約 100 毫秒。
如果你想禁用或自定義此行為,例如在代理後使用 API,你可以傳遞一個 httpAgent
,它將用於所有請求(無論是 http 還是 https),例如:
import http from 'http';
import { HttpsProxyAgent } from 'https-proxy-agent';
// 為所有請求配置默認值:
const client = new Mux({
httpAgent: new HttpsProxyAgent(process.env.PROXY_URL),
});
// 為每個請求覆蓋:
await client.video.assets.retrieve('t02rm...', {
httpAgent: new http.Agent({ keepAlive: false }),
});
🔧 技術細節
語義版本控制
此包通常遵循 SemVer 約定,但某些向後不兼容的更改可能會作為次要版本發佈:
- 僅影響靜態類型,不破壞運行時行為的更改。
- 對庫內部的更改,這些更改在技術上是公開的,但不打算或未記錄供外部使用。(如果你依賴此類內部,請在 GitHub 上打開一個問題告知我們。)
- 我們預計在實踐中不會影響絕大多數用戶的更改。 我們非常重視向後兼容性,並努力確保你能夠依賴平滑的升級體驗。 我們渴望得到你的反饋;請打開一個 問題 提出問題、報告錯誤或提供建議。
要求
支持 TypeScript >= 4.5。 支持以下運行時環境:
- 網頁瀏覽器(最新版本的 Chrome、Firefox、Safari、Edge 等)
- Node.js 18 LTS 或更高版本(非 EOL 版本)。
- Deno v1.28.0 或更高版本。
- Bun 1.0 或更高版本。
- Cloudflare Workers。
- Vercel Edge Runtime。
- Jest 28 或更高版本,使用
"node"
環境(目前不支持"jsdom"
)。 - Nitro v2.6 或更高版本。 請注意,目前不支持 React Native。 如果你對其他運行時環境感興趣,請在 GitHub 上打開或投票支持一個問題。
🤝 貢獻
請參閱 貢獻文檔。













