
TDengine REST API 使用手册
目录
- 概述
- 环境准备
- 快速入门
- [API 详细说明](#API 详细说明)
- [HTTP 请求格式](#HTTP 请求格式)
- 认证机制
- [HTTP 响应格式](#HTTP 响应格式)
- 高级功能
- 最佳实践
- 常见问题
- 版本差异说明
概述
TDengine 提供符合 RESTful 设计标准的 HTTP API,通过简单的 HTTP 请求即可操作数据库。为降低学习成本,TDengine 采用独特的设计:直接在 HTTP POST 请求体中包含 SQL 语句来操作数据库,仅需一个 URL 即可完成所有操作。
适用场景
REST API 特别适合以下应用场景:
| 场景 | 说明 | 典型应用 |
|---|---|---|
| 跨平台开发 | 适用于任何支持 HTTP 协议的编程语言和平台 | 嵌入式系统、移动应用、Web 应用 |
| 轻量级客户端 | 无需安装 TDengine 客户端库,降低部署复杂度 | IoT 设备、边缘计算节点 |
| 微服务架构 | 与容器化、微服务架构完美契合 | Docker、Kubernetes 环境 |
| 快速原型开发 | 使用 curl、Postman 等工具即可快速验证 | POC、Demo、调试 |
| 云原生应用 | 特别适合云环境和 Serverless 架构 | AWS Lambda、Azure Functions |
| 防火墙友好 | HTTP/HTTPS 协议通常不会被防火墙拦截 | 跨网络边界的数据访问 |
| 异构系统集成 | 作为统一的数据访问接口 | 多语言、多系统集成 |
REST API 的优势
1. 零依赖部署
- ✅ 客户端无需安装任何 TDengine 库或驱动
- ✅ 只需标准的 HTTP 客户端即可
- ✅ 减少依赖冲突和版本兼容性问题
2. 广泛的语言支持
- ✅ Python、Java、Go、Node.js、C#、PHP、Ruby 等所有主流语言
- ✅ 甚至支持 Shell、JavaScript(浏览器)
- ✅ 统一的接口,无需学习不同语言的专用驱动
3. 易于调试和测试
- ✅ 使用 curl、Postman、HTTPie 等通用工具
- ✅ 可以直接在浏览器中测试(使用插件)
- ✅ 方便日志记录和问题排查
4. 架构灵活性
- ✅ 可方便地通过 Nginx、HAProxy 实现负载均衡
- ✅ 支持 API Gateway 统一管理
- ✅ 易于实现高可用架构
5. 安全性
- ✅ 支持 HTTPS 加密传输
- ✅ 多种认证方式:Basic、Token、自定义
- ✅ 可与企业现有的认证系统集成
6. 标准化
- ✅ 遵循 RESTful 设计规范
- ✅ 统一的错误码和响应格式
- ✅ 学习成本低,文档友好
与原生连接器的差异
⚠️ 重要提示
REST API 是无状态接口,每次请求都是独立的,这意味着:
| 特性 | 原生连接器 | REST API |
|---|---|---|
| 状态保持 | ✅ 有状态(支持会话) | ❌ 无状态(每次独立) |
| USE 命令 | ✅ 生效 | ❌ 不生效 |
| 表名前缀 | 可选 | 必须指定数据库名前缀 |
| 性能 | 更高(直接连接) | 略低(HTTP 开销) |
| 安装要求 | 需要安装客户端库 | 无需安装 |
| 连接池 | 内置支持 | 需自行实现或使用 HTTP 连接池 |
解决方案:
- 方案 1:在 SQL 中使用完整表名,如
demo.meters - 方案 2:在 URL 中指定数据库名,如
http://host:6041/rest/sql/demo
环境准备
安装要求
客户端:
- ✅ 无需安装任何 TDengine 组件
- ✅ 只需要支持 HTTP 协议的编程语言或工具
服务端:
- ✅ TDengine Server 2.x 或 3.x
- ✅ taosAdapter 服务(提供 REST API)
服务端配置
1. 确认 TDengine Server 运行状态
bash
# 检查 TDengine Server
systemctl status taosd
# 如未启动,执行启动命令
systemctl start taosd
2. 启动 taosAdapter 服务
bash
# 启动 taosAdapter
systemctl start taosadapter
# 查看服务状态
systemctl status taosadapter
# 设置开机自启
systemctl enable taosadapter
3. 确认端口监听
bash
# 检查 taosAdapter 是否监听 6041 端口(默认)
netstat -tuln | grep 6041
# 或
ss -tuln | grep 6041
4. 配置调整(可选)
编辑配置文件 /etc/taos/taosadapter.toml:
toml
[http]
# REST API 监听端口,默认 6041
port = 6041
# 是否启用 HTTPS
enable = true
# SSL 证书配置(启用 HTTPS 时需要)
# certFile = "/path/to/cert.pem"
# keyFile = "/path/to/key.pem"
[log]
# 日志级别:trace, debug, info, warn, error, panic
level = "info"
修改配置后需要重启服务:
bash
systemctl restart taosadapter
快速入门
连接验证
使用 curl 命令验证 REST API 是否正常工作:
bash
curl -L -H "Authorization: Basic cm9vdDp0YW9zZGF0YQ==" \
-d "SELECT name, ntables, status FROM information_schema.ins_databases;" \
http://localhost:6041/rest/sql
参数说明:
-L:跟随 HTTP 重定向-H:设置 HTTP 请求头(这里是认证信息)-d:POST 请求体(SQL 语句)cm9vdDp0YW9zZGF0YQ==:root:taosdata的 Base64 编码
成功响应示例:
json
{
"code": 0,
"column_meta": [
["name", "VARCHAR", 64],
["ntables", "BIGINT", 8],
["status", "VARCHAR", 10]
],
"data": [
["information_schema", 16, "ready"],
["performance_schema", 9, "ready"]
],
"rows": 2
}
响应字段说明:
code:返回码,0 表示成功column_meta:列元数据(列名、类型、长度)data:查询结果数据rows:返回的行数
基本操作示例
1. 创建数据库
bash
curl -L -H "Authorization: Basic cm9vdDp0YW9zZGF0YQ==" \
-d "CREATE DATABASE IF NOT EXISTS demo KEEP 365 DURATION 10 BUFFER 16" \
http://localhost:6041/rest/sql
响应:
json
{
"code": 0,
"column_meta": [["affected_rows", "INT", 4]],
"data": [[0]],
"rows": 1
}
2. 创建超级表(Super Table)
bash
curl -L -H "Authorization: Basic cm9vdDp0YW9zZGF0YQ==" \
-d "CREATE STABLE IF NOT EXISTS demo.meters (
ts TIMESTAMP,
current FLOAT,
voltage INT,
phase FLOAT
) TAGS (
location BINARY(64),
groupId INT
)" \
http://localhost:6041/rest/sql
3. 创建子表并插入数据
单条插入:
bash
curl -L -H "Authorization: Basic cm9vdDp0YW9zZGF0YQ==" \
-d "INSERT INTO demo.d1001 USING demo.meters TAGS ('California.SanFrancisco', 2)
VALUES (NOW, 10.3, 219, 0.31)" \
http://localhost:6041/rest/sql
批量插入:
bash
curl -L -H "Authorization: Basic cm9vdDp0YW9zZGF0YQ==" \
-d "INSERT INTO
demo.d1001 VALUES
('2024-01-22 10:00:00', 10.2, 220, 0.30)
('2024-01-22 10:00:01', 10.3, 219, 0.31)
('2024-01-22 10:00:02', 10.4, 221, 0.32)
demo.d1002 USING demo.meters TAGS ('California.LosAngeles', 2) VALUES
('2024-01-22 10:00:00', 11.2, 218, 0.28)" \
http://localhost:6041/rest/sql
4. 查询数据
基础查询:
bash
curl -L -H "Authorization: Basic cm9vdDp0YW9zZGF0YQ==" \
-d "SELECT * FROM demo.meters WHERE ts >= NOW - 1h LIMIT 100" \
http://localhost:6041/rest/sql
聚合查询:
bash
curl -L -H "Authorization: Basic cm9vdDp0YW9zZGF0YQ==" \
-d "SELECT
FIRST(ts),
AVG(current),
MAX(voltage),
MIN(phase)
FROM demo.meters
WHERE ts >= NOW - 1d
INTERVAL(1h)
GROUP BY location" \
http://localhost:6041/rest/sql
5. 使用 URL 指定数据库
当在 URL 中指定数据库名后,SQL 语句中可以省略数据库前缀:
bash
# URL 中指定了 demo 数据库
curl -L -H "Authorization: Basic cm9vdDp0YW9zZGF0YQ==" \
-d "SELECT * FROM meters WHERE ts >= NOW - 1h" \
http://localhost:6041/rest/sql/demo
API 详细说明
HTTP 请求格式
URL 格式
text
http://<fqdn>:<port>/rest/sql/[db_name][?tz=timezone][&req_id=req_id][&row_with_meta=true]
参数详解:
| 参数 | 必选 | 说明 | 示例 |
|---|---|---|---|
fqdn |
✅ | TDengine Server 的 FQDN 或 IP 地址 | 192.168.1.100 |
port |
✅ | taosAdapter 监听端口 | 6041(默认) |
db_name |
❌ | 默认数据库名,SQL 中未指定数据库时使用 | demo |
tz |
❌ | 返回时间的时区,遵循 IANA 规则 | America/New_York Asia/Shanghai |
req_id |
❌ | 请求 ID,用于请求追踪和日志关联 | req_20240122_001 |
row_with_meta |
❌ | 是否每行数据携带列名(3.3.2.0+) | true 或 false |
URL 示例:
bash
# 基础 URL
http://192.168.1.100:6041/rest/sql
# 指定数据库
http://192.168.1.100:6041/rest/sql/demo
# 指定时区
http://192.168.1.100:6041/rest/sql?tz=Asia/Shanghai
# 完整参数
http://192.168.1.100:6041/rest/sql/demo?tz=Asia/Shanghai&req_id=req001&row_with_meta=true
HTTP 方法
- POST:所有 SQL 操作都使用 POST 方法
请求头(Headers)
必需的请求头:
http
Content-Type: text/plain
Authorization: <认证类型> <TOKEN>
可选的请求头:
http
Accept: application/json
Accept-Encoding: gzip, deflate
请求体(Body)
请求体包含完整的 SQL 语句:
sql
SELECT * FROM demo.meters WHERE ts >= NOW - 1h;
注意事项:
- ✅ 支持单条或多条 SQL 语句(分号分隔)
- ✅ 支持复杂的 SQL 语法(JOIN、子查询等)
- ❌ 不要在 SQL 中使用
USE database语句(无效)
认证机制
TDengine REST API 支持三种认证方式:
1. Basic 认证(推荐用于测试)
格式:
http
Authorization: Basic <TOKEN>
TOKEN 生成:
bash
# TOKEN = Base64(username:password)
echo -n "root:taosdata" | base64
# 输出:cm9vdDp0YW9zZGF0YQ==
使用示例:
bash
curl -L -H "Authorization: Basic cm9vdDp0YW9zZGF0YQ==" \
-d "SELECT * FROM demo.meters" \
http://localhost:6041/rest/sql
或使用 -u 参数:
bash
curl -L -u root:taosdata \
-d "SELECT * FROM demo.meters" \
http://localhost:6041/rest/sql
2. Token 认证(推荐用于生产环境,3.4.0+)
优势:
- ✅ 更安全(由服务器生成和管理)
- ✅ 支持过期时间
- ✅ 可以撤销
创建 Token:
sql
-- 使用 taos CLI 或其他客户端创建
CREATE TOKEN myapp_token FROM USER root;
返回示例:
text
token: bjUvkeBfqFsrXBSj8QjnORJcN0nyA6vdkLNAbkI2MhbWPt289OnIQcZHDIDa8SR
使用 Token:
bash
curl -L -H "Authorization: Bearer bjUvkeBfqFsrXBSj8QjnORJcN0nyA6vdkLNAbkI2MhbWPt289OnIQcZHDIDa8SR" \
-d "SELECT * FROM demo.meters" \
http://localhost:6041/rest/sql
Token 管理:
sql
-- 查看 Token 列表
SHOW TOKENS;
-- 撤销 Token
DROP TOKEN myapp_token;
3. 自定义授权码
获取授权码:
bash
curl http://localhost:6041/rest/login/root/taosdata
响应:
json
{
"code": 0,
"desc": "/KfeAzX/f9na8qdtNZmtONryp201ma04bEl8LcvLUd7a8qdtNZmtONryp201ma04"
}
使用授权码:
bash
curl -L -H "Authorization: Taosd /KfeAzX/f9na8qdtNZmtONryp201ma04bEl8LcvLUd7a8qdtNZmtONryp201ma04" \
-d "SELECT * FROM demo.meters" \
http://localhost:6041/rest/sql
HTTP 响应格式
HTTP 状态码
TDengine 3.0.3.0+ 提供 httpCodeServerError 配置参数控制错误时的 HTTP 状态码。
当 httpCodeServerError = false(默认):
| 情况 | HTTP 状态码 |
|---|---|
| C 接口调用成功 | 200 |
| C 接口调用出错(非鉴权) | 200 |
| HTTP 请求 URL 参数错误 | 400 |
| C 接口调用鉴权错误 | 401 |
| 接口不存在 | 404 |
| 系统资源不足 | 503 |
当 httpCodeServerError = true:
| 情况 | HTTP 状态码 |
|---|---|
| C 接口调用成功 | 200 |
| URL 参数错误和参数解析错误 | 400 |
| C 接口调用鉴权错误 | 401 |
| 接口不存在 | 404 |
| C 接口调用网络错误 | 502 |
| 系统资源不足 | 503 |
| 其他 C 接口调用错误 | 500 |
响应体格式
成功执行插入操作:
json
{
"code": 0,
"column_meta": [["affected_rows", "INT", 4]],
"data": [[5]],
"rows": 1
}
成功执行查询操作:
json
{
"code": 0,
"column_meta": [
["ts", "TIMESTAMP", 8],
["current", "FLOAT", 4],
["voltage", "INT", 4],
["phase", "FLOAT", 4]
],
"data": [
["2024-01-22T10:00:00.000Z", 10.3, 219, 0.31],
["2024-01-22T10:00:01.000Z", 10.4, 220, 0.32]
],
"rows": 2
}
执行错误:
json
{
"code": 9728,
"desc": "syntax error near \"FORM\""
}
响应字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
code |
int | 返回码,0 表示成功,非 0 表示错误 |
column_meta |
array | 列元数据,格式:[列名, 类型, 长度] |
data |
array | 查询结果数据,二维数组 |
rows |
int | 返回的行数 |
desc |
string | 错误描述(仅错误时) |
数据类型对照表
| TDengine 类型 | REST API 字符串 | JSON 数据类型 | 说明 |
|---|---|---|---|
| TIMESTAMP | "TIMESTAMP" | string | RFC3339 格式 |
| BOOL | "BOOL" | boolean | true/false |
| TINYINT | "TINYINT" | number | -128~127 |
| SMALLINT | "SMALLINT" | number | -32768~32767 |
| INT | "INT" | number | -2³¹~2³¹-1 |
| BIGINT | "BIGINT" | number | -2⁶³~2⁶³-1 |
| FLOAT | "FLOAT" | number | 单精度浮点 |
| DOUBLE | "DOUBLE" | number | 双精度浮点 |
| VARCHAR | "VARCHAR" | string | 变长字符串 |
| NCHAR | "NCHAR" | string | Unicode 字符串 |
| JSON | "JSON" | object | JSON 对象 |
| VARBINARY | "VARBINARY" | string | Hex 字符串 |
| GEOMETRY | "GEOMETRY" | string | WKB Hex 字符串 |
| BLOB | "BLOB" | string | Hex 字符串 |
| DECIMAL | "DECIMAL(M,N)" | string | 定点数 |
特殊类型示例:
GEOMETRY 类型:
bash
# 准备数据
curl -L -u root:taosdata \
-d "CREATE DATABASE IF NOT EXISTS demo;
CREATE TABLE demo.geo_test(ts TIMESTAMP, location GEOMETRY(100));
INSERT INTO demo.geo_test VALUES(NOW, 'POINT(100 100)');" \
http://localhost:6041/rest/sql
# 查询
curl -L -u root:taosdata \
-d "SELECT * FROM demo.geo_test" \
http://localhost:6041/rest/sql
响应:
json
{
"code": 0,
"column_meta": [
["ts", "TIMESTAMP", 8],
["location", "GEOMETRY", 100]
],
"data": [
["2024-01-22T10:00:00.000Z", "010100000000000000000059400000000000005940"]
],
"rows": 1
}
010100000000000000000059400000000000005940是POINT(100 100)的 WKB (Well-Known Binary) 格式的 Hex 表示
高级功能
时区设置
使用 tz 参数指定返回时间的时区:
bash
# 使用上海时区
curl -L -u root:taosdata \
-d "SELECT * FROM demo.meters WHERE ts >= NOW - 1h" \
"http://localhost:6041/rest/sql?tz=Asia/Shanghai"
# 使用纽约时区
curl -L -u root:taosdata \
-d "SELECT * FROM demo.meters WHERE ts >= NOW - 1h" \
"http://localhost:6041/rest/sql?tz=America/New_York"
支持的时区格式:
- IANA 时区数据库格式(推荐):
Asia/Shanghai、America/New_York - UTC 偏移量:
UTC、UTC+8、UTC-5
请求追踪
使用 req_id 参数为请求设置唯一标识,便于问题排查:
bash
curl -L -u root:taosdata \
-d "SELECT * FROM demo.meters" \
"http://localhost:6041/rest/sql?req_id=req_20240122_${RANDOM}"
优势:
- ✅ 在日志中快速定位特定请求
- ✅ 关联前端请求和后端日志
- ✅ 构建分布式追踪系统
查看日志:
bash
# taosAdapter 日志位置
tail -f /var/log/taos/taosadapter.log | grep "req_20240122"
Key-Value 格式返回
使用 row_with_meta=true 参数,将数组格式的数据转换为 JSON 对象格式(3.3.2.0+):
标准格式(默认):
bash
curl -L -u root:taosdata \
-d "SELECT ts, current, voltage FROM demo.d1001 LIMIT 1" \
http://localhost:6041/rest/sql
响应:
json
{
"code": 0,
"column_meta": [
["ts", "TIMESTAMP", 8],
["current", "FLOAT", 4],
["voltage", "INT", 4]
],
"data": [
["2024-01-22T10:00:00.000Z", 10.3, 219]
],
"rows": 1
}
Key-Value 格式:
bash
curl -L -u root:taosdata \
-d "SELECT ts, current, voltage FROM demo.d1001 LIMIT 1" \
"http://localhost:6041/rest/sql?row_with_meta=true"
响应:
json
{
"code": 0,
"column_meta": [
["ts", "TIMESTAMP", 8],
["current", "FLOAT", 4],
["voltage", "INT", 4]
],
"data": [
{
"ts": "2024-01-22T10:00:00.000Z",
"current": 10.3,
"voltage": 219
}
],
"rows": 1
}
使用场景:
- ✅ 前端开发,直接使用对象属性
- ✅ 动态列查询,列数不固定
- ✅ 提高代码可读性
最佳实践
1. 性能优化
批量操作
bash
# ❌ 不推荐:多次单条插入
for i in {1..100}; do
curl -L -u root:taosdata \
-d "INSERT INTO demo.d1001 VALUES (NOW, $i, 220, 0.3)" \
http://localhost:6041/rest/sql
done
# ✅ 推荐:批量插入
curl -L -u root:taosdata \
-d "INSERT INTO demo.d1001 VALUES
('2024-01-22 10:00:00', 10.1, 220, 0.30)
('2024-01-22 10:00:01', 10.2, 219, 0.31)
('2024-01-22 10:00:02', 10.3, 221, 0.32)
... (更多数据)" \
http://localhost:6041/rest/sql
使用连接池
Python 示例:
python
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
# 创建会话并配置连接池
session = requests.Session()
retries = Retry(total=3, backoff_factor=0.1)
adapter = HTTPAdapter(pool_connections=10, pool_maxsize=20, max_retries=retries)
session.mount('http://', adapter)
# 使用会话发送请求
response = session.post(
'http://localhost:6041/rest/sql',
headers={'Authorization': 'Basic cm9vdDp0YW9zZGF0YQ=='},
data='SELECT * FROM demo.meters'
)
限制返回结果集大小
bash
# 使用 LIMIT 限制返回行数
curl -L -u root:taosdata \
-d "SELECT * FROM demo.meters WHERE ts >= NOW - 1d LIMIT 1000" \
http://localhost:6041/rest/sql
2. 安全实践
使用 HTTPS
配置 taosAdapter HTTPS:
toml
# /etc/taos/taosadapter.toml
[http]
enable = true
port = 6041
[https]
enable = true
port = 6043
certFile = "/path/to/cert.pem"
keyFile = "/path/to/key.pem"
使用 HTTPS 请求:
bash
curl -L -u root:taosdata \
-d "SELECT * FROM demo.meters" \
https://localhost:6043/rest/sql
避免在 URL 中暴露密码
bash
# ❌ 不推荐:密码可能被记录到日志
curl -L -u root:taosdata \
-d "SELECT * FROM demo.meters" \
http://localhost:6041/rest/sql
# ✅ 推荐:使用环境变量
export TDENGINE_USER="root"
export TDENGINE_PASS="taosdata"
export TDENGINE_AUTH=$(echo -n "$TDENGINE_USER:$TDENGINE_PASS" | base64)
curl -L -H "Authorization: Basic $TDENGINE_AUTH" \
-d "SELECT * FROM demo.meters" \
http://localhost:6041/rest/sql
使用 Token 认证(生产环境)
bash
# 1. 创建专用 Token
taos> CREATE TOKEN app_readonly FROM USER readonly_user;
# 2. 在应用中使用 Token
export TDENGINE_TOKEN="bjUvkeBfqFsrXBSj8QjnORJcN0nyA6vdkLNAbkI2MhbWPt289OnIQcZHDIDa8SR"
curl -L -H "Authorization: Bearer $TDENGINE_TOKEN" \
-d "SELECT * FROM demo.meters" \
http://localhost:6041/rest/sql
# 3. 需要时撤销 Token
taos> DROP TOKEN app_readonly;
3. 错误处理
完整的错误处理示例(Python)
python
import requests
import json
def execute_sql(sql, database=None):
"""执行 TDengine SQL 语句"""
url = f"http://localhost:6041/rest/sql"
if database:
url += f"/{database}"
headers = {
'Authorization': 'Basic cm9vdDp0YW9zZGF0YQ=='
}
try:
response = requests.post(url, headers=headers, data=sql, timeout=30)
# 检查 HTTP 状态码
if response.status_code == 401:
return {"success": False, "error": "认证失败,请检查用户名和密码"}
elif response.status_code == 404:
return {"success": False, "error": "接口不存在,请检查 URL"}
elif response.status_code == 503:
return {"success": False, "error": "服务不可用,请稍后重试"}
elif response.status_code != 200:
return {"success": False, "error": f"HTTP 错误:{response.status_code}"}
# 解析响应
result = response.json()
# 检查业务状态码
if result.get('code') == 0:
return {
"success": True,
"data": result.get('data', []),
"rows": result.get('rows', 0),
"columns": result.get('column_meta', [])
}
else:
return {
"success": False,
"error": f"SQL 执行错误 [{result.get('code')}]: {result.get('desc', '未知错误')}"
}
except requests.exceptions.Timeout:
return {"success": False, "error": "请求超时"}
except requests.exceptions.ConnectionError:
return {"success": False, "error": "连接失败,请检查服务是否运行"}
except json.JSONDecodeError:
return {"success": False, "error": "响应格式错误"}
except Exception as e:
return {"success": False, "error": f"未知错误: {str(e)}"}
# 使用示例
result = execute_sql("SELECT * FROM demo.meters LIMIT 10", database="demo")
if result['success']:
print(f"查询成功,返回 {result['rows']} 行数据")
for row in result['data']:
print(row)
else:
print(f"查询失败:{result['error']}")
4. 监控和日志
启用详细日志
toml
# /etc/taos/taosadapter.toml
[log]
level = "debug" # trace, debug, info, warn, error
path = "/var/log/taos"
rotationCount = 30
rotationSize = "1GB"
监控关键指标
bash
# 监控 taosAdapter 进程
ps aux | grep taosadapter
# 监控端口连接数
netstat -an | grep :6041 | wc -l
# 查看最近的错误日志
tail -n 100 /var/log/taos/taosadapter.log | grep ERROR
# 监控请求延迟(在日志中)
tail -f /var/log/taos/taosadapter.log | grep "cost"
常见问题
Q1: 为什么返回 401 未授权错误?
可能原因:
- Base64 编码错误
- 用户名或密码错误
- 用户权限不足
解决方法:
bash
# 1. 验证 Base64 编码
echo -n "root:taosdata" | base64
# 输出应该是:cm9vdDp0YW9zZGF0YQ==
# 2. 使用 taos CLI 验证账号
taos -u root -p taosdata
# 3. 检查用户权限
taos> SHOW USERS;
Q2: 为什么 USE 命令不生效?
REST API 是无状态的,USE 命令不会生效。
解决方法:
bash
# 方法 1:在 SQL 中使用完整表名
curl -L -u root:taosdata \
-d "SELECT * FROM demo.meters" \
http://localhost:6041/rest/sql
# 方法 2:在 URL 中指定数据库
curl -L -u root:taosdata \
-d "SELECT * FROM meters" \
http://localhost:6041/rest/sql/demo
Q3: 如何处理大量数据的插入?
建议:
- 批量插入,每批 1000-10000 条
- 使用多线程并发插入
- 优化数据格式,减少 JSON 解析开销
python
# Python 批量插入示例
def batch_insert(data_list, batch_size=5000):
for i in range(0, len(data_list), batch_size):
batch = data_list[i:i+batch_size]
values = ", ".join([f"('{row[0]}', {row[1]}, {row[2]}, {row[3]})"
for row in batch])
sql = f"INSERT INTO demo.d1001 VALUES {values}"
execute_sql(sql)
Q4: 时间戳格式问题
问题: 时间戳显示为 UTC 时区,如何转换?
解决方法:
bash
# 方法 1:使用 tz 参数
curl -L -u root:taosdata \
-d "SELECT * FROM demo.meters" \
"http://localhost:6041/rest/sql?tz=Asia/Shanghai"
# 方法 2:在客户端转换
# Python 示例
from datetime import datetime
import pytz
utc_time = "2024-01-22T10:00:00.000Z"
dt = datetime.fromisoformat(utc_time.replace('Z', '+00:00'))
local_time = dt.astimezone(pytz.timezone('Asia/Shanghai'))
print(local_time) # 2024-01-22 18:00:00+08:00
Q5: 如何实现负载均衡?
使用 Nginx 作为反向代理:
nginx
# /etc/nginx/nginx.conf
upstream tdengine_api {
least_conn; # 最少连接数算法
server 192.168.1.10:6041 weight=1 max_fails=3 fail_timeout=30s;
server 192.168.1.11:6041 weight=1 max_fails=3 fail_timeout=30s;
server 192.168.1.12:6041 weight=1 max_fails=3 fail_timeout=30s;
}
server {
listen 80;
server_name tdengine.example.com;
location /rest/ {
proxy_pass http://tdengine_api;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
}
Q6: 如何调试 REST API 请求?
方法 1:使用 curl 的详细输出
bash
curl -v -L -u root:taosdata \
-d "SELECT * FROM demo.meters" \
http://localhost:6041/rest/sql
方法 2:使用 HTTPie(更友好的输出)
bash
# 安装 HTTPie
pip install httpie
# 发送请求
http POST http://localhost:6041/rest/sql \
Authorization:"Basic cm9vdDp0YW9zZGF0YQ==" \
Content-Type:text/plain \
--raw "SELECT * FROM demo.meters"
方法 3:使用 Postman
- 创建新的 POST 请求
- URL:
http://localhost:6041/rest/sql - Headers:
Authorization: Basic cm9vdDp0YW9zZGF0YQ==Content-Type: text/plain
- Body(raw):
SELECT * FROM demo.meters
版本差异说明
TDengine 2.x vs 3.x
URI 支持
| URI | TDengine 2.x | TDengine 3.x |
|---|---|---|
/rest/sql |
✅ 支持 | ✅ 支持(响应格式不同) |
/rest/sqlt |
✅ 支持 | ❌ 不再支持 |
/rest/sqlutc |
✅ 支持 | ❌ 不再支持 |
HTTP 状态码
| 状态码 | TDengine 2.x | TDengine 3.x | 说明 |
|---|---|---|---|
| 200 | ✅ | ✅ | 正常响应和错误响应 |
| 400 | ❌ | ✅ | 参数错误 |
| 401 | ❌ | ✅ | 认证失败 |
| 404 | ✅ | ✅ | 接口不存在 |
| 500 | ❌ | ✅ | 内部错误 |
| 503 | ✅ | ✅ | 资源不足 |
响应格式差异
TDengine 2.x:
json
{
"status": "succ",
"head": ["name", "created_time", "ntables", ...],
"data": [
["log", "2020-09-02 17:23:00.039", 4, ...]
],
"rows": 1
}
TDengine 3.x:
json
{
"code": 0,
"column_meta": [
["name", "VARCHAR", 64],
["ntables", "BIGINT", 8],
...
],
"data": [
["information_schema", 16, "ready"]
],
"rows": 1
}
主要变化:
status→code(0 表示成功)head→column_meta(包含类型和长度信息)- 数据格式保持一致
附录
完整示例代码
Python
python
import requests
import json
from typing import Optional, Dict, List, Any
class TDengineRestClient:
"""TDengine REST API 客户端"""
def __init__(self, host: str = "localhost", port: int = 6041,
username: str = "root", password: str = "taosdata",
database: Optional[str] = None, use_https: bool = False):
self.base_url = f"{'https' if use_https else 'http'}://{host}:{port}/rest/sql"
if database:
self.base_url += f"/{database}"
import base64
auth_str = f"{username}:{password}"
auth_bytes = auth_str.encode('utf-8')
auth_b64 = base64.b64encode(auth_bytes).decode('utf-8')
self.headers = {
'Authorization': f'Basic {auth_b64}',
'Content-Type': 'text/plain'
}
def execute(self, sql: str, tz: Optional[str] = None,
req_id: Optional[str] = None) -> Dict[str, Any]:
"""执行 SQL 语句"""
url = self.base_url
params = {}
if tz:
params['tz'] = tz
if req_id:
params['req_id'] = req_id
try:
response = requests.post(url, headers=self.headers,
data=sql, params=params, timeout=30)
result = response.json()
if result.get('code') == 0:
return {
'success': True,
'data': result.get('data', []),
'rows': result.get('rows', 0),
'columns': result.get('column_meta', [])
}
else:
return {
'success': False,
'error_code': result.get('code'),
'error': result.get('desc', 'Unknown error')
}
except Exception as e:
return {
'success': False,
'error': str(e)
}
def query(self, sql: str) -> List[Any]:
"""查询数据"""
result = self.execute(sql)
if result['success']:
return result['data']
else:
raise Exception(result.get('error', 'Query failed'))
def insert(self, sql: str) -> int:
"""插入数据,返回受影响行数"""
result = self.execute(sql)
if result['success']:
return result['data'][0][0] if result['data'] else 0
else:
raise Exception(result.get('error', 'Insert failed'))
# 使用示例
if __name__ == "__main__":
# 创建客户端
client = TDengineRestClient(host="localhost", database="demo")
# 创建数据库和表
client.execute("CREATE DATABASE IF NOT EXISTS demo")
client.execute("""
CREATE STABLE IF NOT EXISTS demo.meters (
ts TIMESTAMP,
current FLOAT,
voltage INT,
phase FLOAT
) TAGS (
location BINARY(64),
groupId INT
)
""")
# 插入数据
affected = client.insert("""
INSERT INTO demo.d1001 USING demo.meters TAGS ('California.SanFrancisco', 2)
VALUES (NOW, 10.3, 219, 0.31)
""")
print(f"Inserted {affected} rows")
# 查询数据
rows = client.query("SELECT * FROM demo.meters LIMIT 10")
for row in rows:
print(row)
JavaScript (Node.js)
javascript
const axios = require('axios');
class TDengineRestClient {
constructor(options = {}) {
const {
host = 'localhost',
port = 6041,
username = 'root',
password = 'taosdata',
database = null,
useHttps = false
} = options;
this.baseURL = `${useHttps ? 'https' : 'http'}://${host}:${port}/rest/sql`;
if (database) {
this.baseURL += `/${database}`;
}
const auth = Buffer.from(`${username}:${password}`).toString('base64');
this.headers = {
'Authorization': `Basic ${auth}`,
'Content-Type': 'text/plain'
};
}
async execute(sql, options = {}) {
const { tz, reqId } = options;
const params = {};
if (tz) params.tz = tz;
if (reqId) params.req_id = reqId;
try {
const response = await axios.post(this.baseURL, sql, {
headers: this.headers,
params: params,
timeout: 30000
});
const result = response.data;
if (result.code === 0) {
return {
success: true,
data: result.data || [],
rows: result.rows || 0,
columns: result.column_meta || []
};
} else {
return {
success: false,
errorCode: result.code,
error: result.desc || 'Unknown error'
};
}
} catch (error) {
return {
success: false,
error: error.message
};
}
}
async query(sql) {
const result = await this.execute(sql);
if (result.success) {
return result.data;
} else {
throw new Error(result.error || 'Query failed');
}
}
async insert(sql) {
const result = await this.execute(sql);
if (result.success) {
return result.data[0]?.[0] || 0;
} else {
throw new Error(result.error || 'Insert failed');
}
}
}
// 使用示例
(async () => {
const client = new TDengineRestClient({ database: 'demo' });
// 创建数据库和表
await client.execute('CREATE DATABASE IF NOT EXISTS demo');
await client.execute(`
CREATE STABLE IF NOT EXISTS demo.meters (
ts TIMESTAMP,
current FLOAT,
voltage INT,
phase FLOAT
) TAGS (
location BINARY(64),
groupId INT
)
`);
// 插入数据
const affected = await client.insert(`
INSERT INTO demo.d1001 USING demo.meters TAGS ('California.SanFrancisco', 2)
VALUES (NOW, 10.3, 219, 0.31)
`);
console.log(`Inserted ${affected} rows`);
// 查询数据
const rows = await client.query('SELECT * FROM demo.meters LIMIT 10');
console.log(rows);
})();
Go
go
package main
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"time"
)
type TDengineRestClient struct {
baseURL string
headers map[string]string
client *http.Client
}
type Response struct {
Code int `json:"code"`
ColumnMeta [][]any `json:"column_meta"`
Data [][]any `json:"data"`
Rows int `json:"rows"`
Desc string `json:"desc"`
}
func NewTDengineRestClient(host string, port int, username, password, database string) *TDengineRestClient {
baseURL := fmt.Sprintf("http://%s:%d/rest/sql", host, port)
if database != "" {
baseURL += "/" + database
}
auth := base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
return &TDengineRestClient{
baseURL: baseURL,
headers: map[string]string{
"Authorization": "Basic " + auth,
"Content-Type": "text/plain",
},
client: &http.Client{
Timeout: 30 * time.Second,
},
}
}
func (c *TDengineRestClient) Execute(sql string) (*Response, error) {
req, err := http.NewRequest("POST", c.baseURL, bytes.NewBufferString(sql))
if err != nil {
return nil, err
}
for k, v := range c.headers {
req.Header.Set(k, v)
}
resp, err := c.client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var result Response
err = json.Unmarshal(body, &result)
if err != nil {
return nil, err
}
if result.Code != 0 {
return &result, fmt.Errorf("SQL error [%d]: %s", result.Code, result.Desc)
}
return &result, nil
}
func main() {
client := NewTDengineRestClient("localhost", 6041, "root", "taosdata", "demo")
// 创建数据库
_, err := client.Execute("CREATE DATABASE IF NOT EXISTS demo")
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
// 查询数据
result, err := client.Execute("SELECT * FROM demo.meters LIMIT 10")
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Returned %d rows\n", result.Rows)
for _, row := range result.Data {
fmt.Println(row)
}
}
常用 SQL 模板
bash
# 数据库操作
CREATE DATABASE IF NOT EXISTS mydb KEEP 365 DURATION 10 BUFFER 16;
DROP DATABASE IF EXISTS mydb;
SHOW DATABASES;
# 超级表操作
CREATE STABLE IF NOT EXISTS mydb.meters (
ts TIMESTAMP,
current FLOAT,
voltage INT
) TAGS (location BINARY(64), groupId INT);
SHOW STABLES;
DESCRIBE mydb.meters;
# 子表操作
CREATE TABLE mydb.d1001 USING mydb.meters TAGS ('Beijing', 1);
INSERT INTO mydb.d1001 VALUES (NOW, 10.3, 219);
# 查询操作
SELECT * FROM mydb.meters WHERE ts >= NOW - 1h;
SELECT AVG(current), location FROM mydb.meters WHERE ts >= NOW - 1d GROUP BY location;
SELECT FIRST(ts), LAST(ts), COUNT(*) FROM mydb.meters;
# 聚合查询
SELECT AVG(current), MAX(voltage), location
FROM mydb.meters
WHERE ts >= NOW - 1d
INTERVAL(1h)
GROUP BY location;
总结
TDengine REST API 为开发者提供了一种简单、灵活、跨平台的数据库访问方式。通过本手册,你应该已经掌握:
✅ REST API 的适用场景和优势
✅ 如何配置和使用 REST API
✅ 完整的 API 规范和参数说明
✅ 三种认证机制的使用方法
✅ 性能优化和安全最佳实践
✅ 常见问题的解决方法
✅ 多种编程语言的实现示例
推荐学习资源:
获取帮助:
- GitHub Issues: https://github.com/taosdata/TDengine/issues
- 论坛:https://www.taosdata.com/forum
- 技术支持:support@taosdata.com
关于 TDengine
TDengine 专为物联网IoT平台、工业大数据平台设计。其中,TDengine TSDB 是一款高性能、分布式的时序数据库(Time Series Database),同时它还带有内建的缓存、流式计算、数据订阅等系统功能;TDengine IDMP 是一款AI原生工业数据管理平台,它通过树状层次结构建立数据目录,对数据进行标准化、情景化,并通过 AI 提供实时分析、可视化、事件管理与报警等功能。