tencent cloud

调用方式

下载
聚焦模式
字号
最后更新时间: 2026-09-24 16:27:08
本文档说明平台 FHIR Restful 接口的通用调用方式,包括请求结构、公共参数、接口鉴权以及返回结果。调用方在访问 FHIR 资源接口前,需先通过 API 密钥和签名机制获取 AccessToken,再以 Bearer Token 方式访问业务接口。

请求结构

平台调用过程分为两个阶段:
调用鉴权服务,使用 API Key、时间戳和签名换取 AccessToken。
在访问 FHIR Restful 接口时,通过 Authorization: Bearer <AccessToken> 携带访问令牌。

鉴权服务请求结构

请求方式:
POST /cmd/GetAccessToken HTTP/1.1
Host: <FHIR_SERVICE_HOST>
Content-Type: application/json
说明:
<FHIR_SERVICE_HOST> 为鉴权服务访问域名,请以腾讯健康数据服务控制台实例接入信息或部署方提供的服务访问地址为准。
示例中的 <FHIR_SERVICE_HOST> 仅为占位符,调用时需替换为实际可访问域名,不要直接使用占位符发起请求。
请求体结构:
{
"header": {
"version": "v0.1",
"flag": 0
},
"body": {
"seq": 0,
"cmd": "",
"token": "",
"traceid": "",
"client": {
"platform": 0,
"env": "",
"isTourist": 0,
"product": 0
},
"payload": {
"timestamp": 1730000000000,
"apiKey": "<API_KEY>",
"signature": "<SIGNATURE>",
"scopes": [],
"context": {}
}
}
}
说明:
timestamp 为毫秒级 Unix 时间戳。
signature 为基于 API Secret 计算得到的签名值。
scopes 和 context 为扩展字段,可按实际授权场景传入。

FHIR Restful 请求结构

请求方式根据接口能力不同而变化,常见方法如下:
POST:创建资源,或提交 Bundle 事务/批处理请求。
GET:读取资源、读取历史版本、执行搜索。
PUT:更新完整资源内容。
PATCH:更新局部字段。
DELETE:删除指定资源。
通用请求示例:
GET /INSTANCE_ID/fhir/Patient/199963 HTTP/1.1
Host: HOSTNAME
Authorization: Bearer <AccessToken>
Accept: application/fhir+json
其中,HOSTNAME 为 FHIR 服务访问域名,INSTANCE_ID 为 FHIR 服务实例 ID。请在 腾讯健康数据服务控制台 的实例接入信息中获取,或以部署方提供的服务访问地址为准。
请求地址通常采用以下形式:
资源读写:[baseUrl]/[resourceType] 或 [baseUrl]/[resourceType]/[id]
历史版本读取:[baseUrl]/[resourceType]/[id]/_history/[versionId]
搜索:[baseUrl]/[resourceType]?[searchParams]
患者全量信息检索:[baseUrl]/Patient/[id]/$everything
Bundle 事务/批处理:[baseUrl]

公共参数

鉴权请求公共参数

参数名称
类型
是否必填
说明
header.version
String
是
请求协议版本,示例为 v0.1
header.flag
Integer
是
请求标记,示例为 0
body.seq
Integer
是
请求序号,示例为 0
body.cmd
String
否
预留命令字段
body.token
String
否
预留令牌字段,获取 AccessToken 时通常为空
body.traceid
String
否
请求链路追踪标识
body.client.platform
Integer
否
客户端平台标识
body.client.env
String
否
调用环境标识
body.client.isTourist
Integer
否
游客标识
body.client.product
Integer
否
产品标识
body.payload.timestamp
Integer
是
毫秒级时间戳。服务端允许的时间窗口为请求到达服务端时间前后3600000毫秒(1小时),超出窗口会被拒绝
body.payload.apiKey
String
是
API 密钥
body.payload.signature
String
是
签名值
body.payload.scopes
Array
条件必填
申请的权限范围。开启知情同意访问控制时必填,且至少含1个 actor/<资源类型>/<ID>(如 "actor/Practitioner/P001"),否则访问 FHIR 接口返回401(Claims 中缺少 scope 字段)。未开启时可留空([])
body.payload.context
Object
否
上下文扩展参数

FHIR 请求公共参数

参数名称
类型
是否必填
说明
Host
String
是
FHIR 服务访问域名,例如 HOSTNAME。请在 腾讯健康数据服务控制台 的实例接入信息中获取,或以部署方提供的服务访问地址为准
Authorization
String
是
访问令牌,格式为 Bearer <AccessToken>
Content-Type
String
否
请求体类型,写入类请求通常为 application/fhir+json;Patch 请求通常为 application/json-patch+json
Accept
String
否
响应格式,建议使用 application/fhir+json
resourceType
String
视接口而定
FHIR 资源类型,如 Patient、Observation、Encounter
id
String
视接口而定
资源唯一标识
searchParams
Query String
否
搜索参数,用于筛选结果集
versionId
String
否
历史版本号,用于 vRead 等场景

接口鉴权

平台采用基于 API Key、API Secret 和签名机制的令牌鉴权方式。调用方需先向鉴权服务申请 AccessToken,再携带该令牌访问 FHIR 接口。

鉴权流程

调用方持有服务对应的 API Key 和 API Secret。
调用方生成毫秒级时间戳 timestamp。
调用方使用签名算法生成 signature。
调用方将 apiKey、timestamp、signature 提交至鉴权接口。
鉴权服务校验签名和时间戳有效性。
校验通过后返回基于 JWT 的 AccessToken。
调用方在访问 FHIR Restful 接口时通过 Authorization 请求头携带该令牌。
FHIR 服务收到请求后校验 AccessToken。
校验通过则返回业务结果,校验失败则拒绝访问。

签名算法

签名原文拼接方式:
message = apiKey + timestamp
签名算法:
signature = HMAC-SHA256(apiSecret, message)
说明:
message 使用 UTF-8 编码。
timestamp 为毫秒级时间戳。
签名结果使用十六进制字符串表示。
示例代码显式返回大写十六进制字符串;服务端进行校验时对签名大小写不敏感。

时间戳校验规则

服务端会校验请求时间戳是否在允许的超时时间窗口内。当前允许的时间窗口为请求到达服务端时间前后 3600000 毫秒(1 小时):
若 timestamp > 服务端当前时间 + 3600000,请求将被拒绝。
若 timestamp < 服务端当前时间 - 3600000,请求将被拒绝。
典型失败情况如下:
signTime is timed out
signature is invalid

访问令牌使用方式

获取到 AccessToken 后,调用方需在访问 FHIR 接口时将其放入 HTTP Header:
Authorization: Bearer <AccessToken>
字段说明如下:
Header Key:Authorization
Header Value:Bearer <空格><AccessToken>

示例代码

签名获取 access_token 方法。
import hashlib
import hmac
import time
from typing import Optional

import requests


def sign(api_key: str, api_secret: str, sign_time: int) -> str:
"""签名

Args:
api_key: API密钥
api_secret: API密钥对应的秘密
sign_time: 签名时间(毫秒)

Returns:
签名字符串(大写十六进制)
"""
message = f"{api_key}{sign_time}".encode("utf-8")
h = hmac.new(api_secret.encode("utf-8"), message, hashlib.sha256)
return h.hexdigest().upper()


# 校验签名逻辑(本地自测用)
def check_signature(api_key: str, api_secret: str, signature: str, sign_time: int, timeout: int) -> Optional[str]:
"""校验签名

Args:
api_key: API密钥
api_secret: API密钥对应的秘密
signature: 签名字符串
sign_time: 签名时间(毫秒)
timeout: 超时时间(毫秒)

Returns:
None表示校验通过,否则返回错误信息
"""
now_time = int(time.time() * 1000) # 当前时间(毫秒)

if sign_time > now_time + timeout or sign_time < now_time - timeout:
return "signTime is timed out"

calculated_sign = sign(api_key, api_secret, sign_time)
if signature.upper() != calculated_sign.upper():
return "signature is invalid"

return None


def request_auth_server(api_key: str, api_secret: str) -> Optional[str]:
sign_time = int(time.time() * 1000)
signature = sign(api_key, api_secret, sign_time)

rsp = requests.post(
# 将 <FHIR_SERVICE_HOST> 替换为实际鉴权服务访问域名
url="https://<FHIR_SERVICE_HOST>/cmd/GetAccessToken",
json={
"header": {
"version": "v0.1",
"flag": 0,
},
"body": {
"seq": 0,
"cmd": "",
"token": "",
"traceid": "",
"client": {
"platform": 0,
"env": "",
"isTourist": 0,
"product": 0,
},
"payload": {
"timestamp": sign_time,
"apiKey": api_key,
"signature": signature,
"scopes": [],
"context": {},
},
},
},
timeout=10,
)

if rsp.status_code != 200:
return None

data = rsp.json()
if data.get("retcode", 0) != 0:
return None

payload = data.get("payload") or {}
return payload.get("accessToken")


if __name__ == "__main__":
key = "<KEY>"
secret = "<SECRET>"
token = request_auth_server(key, secret)
print(token)

返回结果

鉴权接口返回结果

鉴权接口调用成功后,返回结果中包含 accessToken,调用方应妥善保存并在后续 FHIR 请求中使用。返回结果示例如下:
{
"payload": {
"accessToken": "<ACCESS_TOKEN>"
}
}
若鉴权接口调用失败,可能出现以下情况:
HTTP 状态码非 200。
响应中未返回 accessToken。
签名校验失败或时间戳失效。

FHIR 接口返回结果

FHIR 接口返回结果遵循标准 FHIR 资源结构,不同接口场景返回内容不同:
资源创建、更新、读取类接口:通常返回对应资源内容。
搜索类接口:通常返回 Bundle。
删除类接口:通常返回 OperationOutcome 或状态结果。
事务/批处理类接口:通常返回结果 Bundle。
常见返回头包括:
参数名称
说明
Status Code
HTTP 状态码,用于标识请求处理结果
ETag
资源版本标识
Location / Content-Location
资源或历史版本访问地址

返回结果处理

对写入类接口,建议结合 Status Code、ETag 和 Location 判断是否写入成功。
对搜索类接口,建议优先解析 Bundle.entry、Bundle.total 和 Bundle.link。
对删除和异常场景,建议结合 OperationOutcome 或错误响应体定位具体原因。


帮助和支持

本页内容是否解决了您的问题?

填写满意度调查问卷,共创更好文档体验。

文档反馈