API 与自动化 #
Platform API 概述 #
Heroku Platform API 允许通过 REST API 管理应用的各个方面,实现自动化运维。
API 特点 #
| 特点 | 说明 |
|---|---|
| RESTful | 标准 REST API |
| JSON 格式 | 请求和响应都是 JSON |
| OAuth 认证 | 使用 Bearer Token |
| 速率限制 | 每小时 4500 请求 |
API 基础 URL #
text
https://api.heroku.com
认证 #
获取 API Token #
bash
# 创建 API Token
heroku authorizations:create
# 输出示例
# Client: <none>
# ID: 12345678-1234-1234-1234-123456789012
# Description: Long-lived user authorization
# Scope: global
# Token: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
# Updated at: Mon Jan 15 2024 10:00:00 GMT+0000
# 或在 Dashboard 创建
# https://dashboard.heroku.com/account/applications
使用 API Token #
bash
# 使用 curl
curl -n https://api.heroku.com/apps \
-H "Accept: application/vnd.heroku+json; version=3"
# 使用 Token
curl https://api.heroku.com/apps \
-H "Accept: application/vnd.heroku+json; version=3" \
-H "Authorization: Bearer YOUR_API_TOKEN"
OAuth 认证 #
bash
# 创建 OAuth 客户端
heroku clients:create "My App" https://example.com/auth/callback
# 输出示例
# === My App
# Client ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
# Client Secret: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
应用管理 API #
创建应用 #
bash
curl -X POST https://api.heroku.com/apps \
-H "Accept: application/vnd.heroku+json; version=3" \
-H "Authorization: Bearer $HEROKU_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "my-awesome-app",
"region": "us"
}'
javascript
// Node.js 示例
const Heroku = require('heroku-client');
const heroku = new Heroku({ token: process.env.HEROKU_API_KEY });
async function createApp(name) {
const app = await heroku.post('/apps', {
body: { name, region: 'us' }
});
return app;
}
获取应用信息 #
bash
curl https://api.heroku.com/apps/my-app \
-H "Accept: application/vnd.heroku+json; version=3" \
-H "Authorization: Bearer $HEROKU_API_KEY"
javascript
async function getAppInfo(appName) {
const app = await heroku.get(`/apps/${appName}`);
return app;
}
列出应用 #
bash
curl https://api.heroku.com/apps \
-H "Accept: application/vnd.heroku+json; version=3" \
-H "Authorization: Bearer $HEROKU_API_KEY"
javascript
async function listApps() {
const apps = await heroku.get('/apps');
return apps;
}
删除应用 #
bash
curl -X DELETE https://api.heroku.com/apps/my-app \
-H "Accept: application/vnd.heroku+json; version=3" \
-H "Authorization: Bearer $HEROKU_API_KEY"
javascript
async function deleteApp(appName) {
await heroku.delete(`/apps/${appName}`);
}
Dyno 管理 API #
列出 Dynos #
bash
curl https://api.heroku.com/apps/my-app/dynos \
-H "Accept: application/vnd.heroku+json; version=3" \
-H "Authorization: Bearer $HEROKU_API_KEY"
javascript
async function listDynos(appName) {
const dynos = await heroku.get(`/apps/${appName}/dynos`);
return dynos;
}
扩展 Dyno #
bash
curl -X PATCH https://api.heroku.com/apps/my-app/formation/web \
-H "Accept: application/vnd.heroku+json; version=3" \
-H "Authorization: Bearer $HEROKU_API_KEY" \
-H "Content-Type: application/json" \
-d '{"quantity": 3}'
javascript
async function scaleDynos(appName, type, quantity) {
const formation = await heroku.patch(`/apps/${appName}/formation/${type}`, {
body: { quantity }
});
return formation;
}
重启 Dyno #
bash
curl -X DELETE https://api.heroku.com/apps/my-app/dynos/web.1 \
-H "Accept: application/vnd.heroku+json; version=3" \
-H "Authorization: Bearer $HEROKU_API_KEY"
javascript
async function restartDyno(appName, dynoName) {
await heroku.delete(`/apps/${appName}/dynos/${dynoName}`);
}
配置管理 API #
获取配置变量 #
bash
curl https://api.heroku.com/apps/my-app/config-vars \
-H "Accept: application/vnd.heroku+json; version=3" \
-H "Authorization: Bearer $HEROKU_API_KEY"
javascript
async function getConfigVars(appName) {
const configVars = await heroku.get(`/apps/${appName}/config-vars`);
return configVars;
}
设置配置变量 #
bash
curl -X PATCH https://api.heroku.com/apps/my-app/config-vars \
-H "Accept: application/vnd.heroku+json; version=3" \
-H "Authorization: Bearer $HEROKU_API_KEY" \
-H "Content-Type: application/json" \
-d '{"NODE_ENV": "production", "DEBUG": "false"}'
javascript
async function setConfigVars(appName, vars) {
const configVars = await heroku.patch(`/apps/${appName}/config-vars`, {
body: vars
});
return configVars;
}
部署 API #
创建构建 #
bash
curl -X POST https://api.heroku.com/apps/my-app/builds \
-H "Accept: application/vnd.heroku+json; version=3" \
-H "Authorization: Bearer $HEROKU_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"source_blob": {
"url": "https://github.com/user/repo/archive/main.tar.gz",
"version": "abc123"
}
}'
javascript
async function createBuild(appName, sourceUrl, version) {
const build = await heroku.post(`/apps/${appName}/builds`, {
body: {
source_blob: {
url: sourceUrl,
version
}
}
});
return build;
}
获取构建状态 #
bash
curl https://api.heroku.com/apps/my-app/builds/build-id \
-H "Accept: application/vnd.heroku+json; version=3" \
-H "Authorization: Bearer $HEROKU_API_KEY"
javascript
async function getBuildStatus(appName, buildId) {
const build = await heroku.get(`/apps/${appName}/builds/${buildId}`);
return build;
}
自动化脚本 #
自动部署脚本 #
javascript
// scripts/deploy.js
const Heroku = require('heroku-client');
const heroku = new Heroku({ token: process.env.HEROKU_API_KEY });
async function deploy(appName, sourceUrl) {
console.log(`Deploying to ${appName}...`);
// 创建构建
const build = await heroku.post(`/apps/${appName}/builds`, {
body: {
source_blob: {
url: sourceUrl
}
}
});
console.log(`Build created: ${build.id}`);
// 等待构建完成
let status = 'pending';
while (status === 'pending') {
await new Promise(resolve => setTimeout(resolve, 5000));
const buildStatus = await heroku.get(`/apps/${appName}/builds/${build.id}`);
status = buildStatus.status;
console.log(`Build status: ${status}`);
}
if (status === 'succeeded') {
console.log('Deployment successful!');
} else {
throw new Error(`Deployment failed: ${status}`);
}
}
deploy('my-app', 'https://github.com/user/repo/archive/main.tar.gz')
.catch(console.error);
自动扩展脚本 #
javascript
// scripts/scale.js
const Heroku = require('heroku-client');
const heroku = new Heroku({ token: process.env.HEROKU_API_KEY });
async function scaleBasedOnTime(appName) {
const hour = new Date().getHours();
const isBusinessHours = hour >= 9 && hour < 18;
const quantity = isBusinessHours ? 3 : 1;
console.log(`Scaling ${appName} to ${quantity} dynos...`);
await heroku.patch(`/apps/${appName}/formation/web`, {
body: { quantity }
});
console.log('Scaling complete');
}
scaleBasedOnTime('my-app').catch(console.error);
监控脚本 #
javascript
// scripts/monitor.js
const Heroku = require('heroku-client');
const heroku = new Heroku({ token: process.env.HEROKU_API_KEY });
async function monitorApps() {
const apps = await heroku.get('/apps');
for (const app of apps) {
const dynos = await heroku.get(`/apps/${app.name}/dynos`);
const webDynos = dynos.filter(d => d.type === 'web');
console.log(`\n${app.name}:`);
console.log(` Web Dynos: ${webDynos.length}`);
for (const dyno of webDynos) {
console.log(` - ${dyno.name}: ${dyno.state}`);
}
}
}
monitorApps().catch(console.error);
GitHub Actions 集成 #
完整自动化工作流 #
yaml
# .github/workflows/heroku-automation.yml
name: Heroku Automation
on:
schedule:
- cron: '0 9 * * 1-5' # 工作日 9:00
- cron: '0 18 * * 1-5' # 工作日 18:00
jobs:
scale-up:
runs-on: ubuntu-latest
if: github.event.schedule == '0 9 * * 1-5'
steps:
- name: Scale up
run: |
curl -X PATCH https://api.heroku.com/apps/my-app/formation/web \
-H "Accept: application/vnd.heroku+json; version=3" \
-H "Authorization: Bearer ${{ secrets.HEROKU_API_KEY }}" \
-H "Content-Type: application/json" \
-d '{"quantity": 3}'
scale-down:
runs-on: ubuntu-latest
if: github.event.schedule == '0 18 * * 1-5'
steps:
- name: Scale down
run: |
curl -X PATCH https://api.heroku.com/apps/my-app/formation/web \
-H "Accept: application/vnd.heroku+json; version=3" \
-H "Authorization: Bearer ${{ secrets.HEROKU_API_KEY }}" \
-H "Content-Type: application/json" \
-d '{"quantity": 1}'
SDK 使用 #
Node.js SDK #
bash
npm install heroku-client
javascript
const Heroku = require('heroku-client');
const heroku = new Heroku({ token: process.env.HEROKU_API_KEY });
// 获取应用列表
const apps = await heroku.get('/apps');
// 创建应用
const app = await heroku.post('/apps', {
body: { name: 'my-new-app' }
});
// 更新配置
await heroku.patch('/apps/my-app/config-vars', {
body: { NODE_ENV: 'production' }
});
// 扩展 Dyno
await heroku.patch('/apps/my-app/formation/web', {
body: { quantity: 2 }
});
Python SDK #
bash
pip install heroku3
python
from heroku3 import Heroku
heroku = Heroku(api_key=os.environ.get('HEROKU_API_KEY'))
# 获取应用列表
apps = heroku.apps()
# 获取特定应用
app = heroku.app('my-app')
# 获取 Dynos
dynos = app.dynos()
# 扩展 Dyno
app.process_formation()['web'].scale(3)
最佳实践 #
1. API Token 管理 #
bash
# 为不同用途创建不同的 Token
heroku authorizations:create -d "CI/CD Pipeline" -s deploy
heroku authorizations:create -d "Monitoring" -s read
# 定期轮换 Token
heroku authorizations:revoke <authorization-id>
2. 错误处理 #
javascript
async function safeApiCall(fn, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
return await fn();
} catch (error) {
if (error.statusCode === 429) {
// 速率限制,等待后重试
await new Promise(resolve => setTimeout(resolve, 60000));
continue;
}
throw error;
}
}
}
3. 日志记录 #
javascript
async function deployWithLogging(appName, sourceUrl) {
console.log(`[${new Date().toISOString()}] Starting deployment to ${appName}`);
try {
const build = await createBuild(appName, sourceUrl);
console.log(`[${new Date().toISOString()}] Build created: ${build.id}`);
// 等待构建完成
await waitForBuild(appName, build.id);
console.log(`[${new Date().toISOString()}] Deployment successful`);
} catch (error) {
console.error(`[${new Date().toISOString()}] Deployment failed:`, error);
throw error;
}
}
下一步 #
API 与自动化掌握后,接下来学习 Node.js 应用部署 开始实战!
最后更新:2026-03-28