文件存储安全与临时直链
为保护文件资产安全,接口不返回底层对象存储的永久地址或内部 File ID,而是生成带有访问校验凭据的短时直链(有效期通常为 600 秒)。对于最终完成件(
signed),
仅在所有签署方完成签署且归档文件生成完毕后方可调用。
请求头 (Request Headers)
本接口无特殊请求头,仅需携带标准公共请求头(无需 Idempotency-Key)。详细标头定义与 HMAC-SHA256 签名算法请参阅:公共请求头与验签规范。
请求体参数 (Request Body)
| 参数名 |
类型 |
必填 |
详细描述 |
| document_id |
string |
必填 |
文档唯一 UUID。 |
| type |
string |
可选 |
需要获取的文件类型:
• signed:最终包含全部签署签章的完整归档文件(默认值)。
• original:发起时的原始空白/模版文件。
默认值:signed
|
请求示例 (Request Example)
curl -X POST "https://api.example.com/open/documents/download" \
-H "Content-Type: application/json" \
-H "X-Api-Access-Key: ak_live_d83e201048b94103" \
-H "X-Api-Timestamp: 1789461000000" \
-H "X-Api-Nonce: 00112233445566778899aabbccddeeff" \
-H "X-Api-Signature: SIGNATURE_BASE64" \
-H "X-Api-Enterprise-Id: 1002" \
-d '{
"document_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"type": "signed"
}'
<?php
use DsignSdk\DsignClient;
$client = new DsignClient([
'base_url' => 'https://api.example.com',
'access_key' => 'ak_live_d83e201048b94103',
'secret_key' => 'sk_live_948f2038102941029',
'enterprise_id' => '1002',
]);
$result = $client->documents->download([
'document_id' => '7c9e6679-7425-40de-944b-e07fc1f90ae7',
'type' => 'signed',
]);
echo "下载链接: " . $result['download_url'];
echo "有效时间(秒): " . $result['expires_in'];
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.UUID;
public class DownloadDocumentDemo {
public static void main(String[] args) throws Exception {
String accessKey = "ak_live_d83e201048b94103";
String secretKey = "sk_live_948f2038102941029";
String enterpriseId = "1002";
long timestampMs = System.currentTimeMillis();
String nonce = UUID.randomUUID().toString().replace("-", "");
String jsonBody = "{\n" +
" \"document_id\": \"7c9e6679-7425-40de-944b-e07fc1f90ae7\",\n" +
" \"type\": \"signed\"\n" +
"}";
String signature = DsignSigner.buildSignature(
secretKey, "POST", "/open/documents/download", "", jsonBody,
timestampMs, nonce, enterpriseId, ""
);
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/open/documents/download"))
.header("Content-Type", "application/json; charset=utf-8")
.header("X-Api-Access-Key", accessKey)
.header("X-Api-Timestamp", String.valueOf(timestampMs))
.header("X-Api-Nonce", nonce)
.header("X-Api-Signature", signature)
.header("X-Api-Enterprise-Id", enterpriseId)
.POST(HttpRequest.BodyPublishers.ofString(jsonBody))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("HTTP 状态码: " + response.statusCode());
System.out.println("下载地址响应: " + response.body());
}
}
import requests, json
resp = requests.post("https://api.example.com/open/documents/download",
headers=headers,
data=json.dumps({
"document_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"type": "signed"
})
)
print(resp.json())
const axios = require('axios');
axios.post('https://api.example.com/open/documents/download', {
document_id: '7c9e6679-7425-40de-944b-e07fc1f90ae7',
type: 'signed'
}, { headers }).then(res => console.log(res.data));
响应数据结构 (Response Body)
| 字段名 |
类型 |
详细说明 |
| document_id |
string |
文档唯一 UUID。 |
| type |
string |
实际获取的文件类型:original 或 signed。 |
| download_url |
string |
经过预签名的专属 PDF 短时直链下载地址。
|
| expires_in |
integer |
地址剩余有效时长,单位:秒(例如 600)。 |
响应示例 (Response Example)
{
"code": 0,
"message": "success",
"data": {
"document_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"type": "signed",
"download_url": "https://storage.example.com/contracts/final.pdf?sign=...",
"expires_in": 600
},
"request_id": "req_68dfb7829a10ef4"
}
相关错误码 (Error Codes)
全部公共状态码与安全拦截说明请参阅:全局错误码字典 (Error Codes)。
| HTTP 状态 |
错误码 (code) |
错误标识 (Constant) |
产生原因与排查指引 |
| 404 |
40401 |
NOT_FOUND |
文档 ID 不存在,或非当前凭证归属成员名下的文档。 |
| 409 |
40901 |
RESOURCE_CONFLICT |
请求类型为 signed 但文档尚未全部签署完成或最终归档文件尚未生成。
|