编组
控制台用户中心

澜舟智译

文档中心

澜舟智译

调用说明

请求地址#

发送 POST 请求到:

https://open.langboat.com

通信协议#

澜舟科技机器翻译服务所提供的 API 接口均通过 HTTPS 进行通信,提供高安全性的通信通道。

调用量统计#

按翻译成功的 待翻译文件内的 有效字符数统计用量。

请求参数#

请求头#

请求头参数是否必须描述
Accept固定值 application/json
Authorization用于验证请求合法性的认证信息,值为 AccessKey:signature格式。
Content-Type固定值 application/json
Content-MD5HTTP 协议消息体的 128-bit MD5 散列值转换成 Base64 编码的结果。
Date请求时间,GMT 格式,如: Wed, 20 Apr. 2022 17:01:00 GMT。
x-langboat-signature-nonce唯一随机数,用于防止网络重放攻击。在不同请求中要使用不同的随机数值。
x-langboat-signature-method签名方法,目前只支持 HMAC-SHA256
签名计算方法#
  1. 计算 body 的 MD5 值,然后转换为 Base64 编码,编码后的值设置到 Content-MD5 Header

计算示例:

  • body = {"sourceText": "Where there is a will, there is a way."}
  • MD5(body) = de56791f6534dcfb4937dd5bdb69ae6f (十六进制字符串表示,实际上为字节数组)
  • Base64(MD5(body)) = 3lZ5H2U03PtJN91b22mubw==

Content-MD5 Header: Content-MD5: 3lZ5H2U03PtJN91b22mubw==

  1. 使用请求中的 Header 参数构造待签名的 HeaderToSign:
StringToSign =
HTTP-Verb + "\n" + //HTTP-Verb只支持POST
Accept + “\n” + //Accept为application/json
Content-MD5 + "\n" + //第1步中计算出来的MD5值
Content-Type + "\n" + //Content-Type值为application/json
Date + "\n" + //Date值为GMT时间
x-langboat-signature-method + "\n" + // 只支持 HMAC-SHA256
x-langboat-signature-nonce + "\n";

StringToSign 示例:

POST
application/json
3lZ5H2U03PtJN91b22mubw==
application/json
Mon, 10 Oct 2022 07:11:08 GMT
HMAC-SHA256
42889
  1. 使用请求中的 Queries 构造待签名的 queryToSign。将 query 字符串(?后的所有参数)根据字典排序升序排列并以&分隔,示例如下:
action=translateDoc&domain=general&sourceLanguage=zh&targetLanguage=en
  1. 将上两步构造的规范化字符串按照下面的规则构造成待签名的字符串。
stringToSign = headerStringToSign + queryToSign;
  1. 计算签名 signature。按照 RFC2104的定义,计算待签名字符串 stringToSign 的 HMAC 值,按照 Base64 编码规则把 HMAC 值编码成字符串,并在前面加上 AccessKey ,即得到签名值(Authorization),示例如下:
Signature = Base64(HMAC-SHA256( AccessSecret, UTF-8-Encoding-Of(stringToSign)))
Authorization = AccessKey + ":" + Signature

Signature 示例:LaglFdItD0M/XD/hx0n0bglt0xTlKPuYhRWn4++dHfs=

Authorization 示例: Authorization: 7Bo9ByyiTWRC1Y8KJJQ9cWtNpZLmrgyb:LaglFdItD0M/XD/hx0n0bglt0xTlKPuYhRWn4++dHfs=

提交待翻译文档#

Query 参数#

QUERY参数是否必须描述
action文本翻译固定参数:translateDoc
domain领域代码, 例如通用 general, 支持的代码见 领域代码说明
sourceLanguage源语言代码,例如简体中文 zh,支持的代码见 语种代码说明
targetLanguage目标语言代码,例如英语 en,支持的代码见 语种代码说明
memoryID记忆库ID,指定您创建的记忆库ID,为空则不使用记忆库

Body 参数#

BODY 参数是否必须描述
fileContent待翻译文档内容的Base64编码,文档大小限制:5M
filename文档标题
fileType文档类型,例如 docx

响应体#

成功的响应体是一个 JSON, 示例:

{
"code": 0,
"message": "success",
"data": { "docID": "448a2625-846a-4891-a48f-a43ed7117942" },
"requestId": "402cd89f6e5fecc600c496af2ee63d4a"
}

docID 为文档ID,后续用来下载文档

响应状态码、业务编码#

下面是可能的 HTTP 响应状态码、业务(错误)编码:

HTTP 状态码业务编码描述
2000返回成功
40010400请求异常
40110401鉴权失败,核对 accessKey 和 accessSecret 是否正确
40310403权限不足,查看是否开通服务;或QPS,字符数,次数超过限制
42210422参数错误,核对请求参数
50010500服务异常

错误响应示例

  • 不支持的 domain
{
"code": 10422,
"message": "参数错误,核对请求参数[ 不支持的domain : biology ]",
"requestId": "962132b206f8cedc77e41030b9aac2e6"
}

请求示例#

# request:
curl --request POST 'https://open.langboat-test.cc?action=translateDoc&domain=general&sourceLanguage=zh&memoryID=38&targetLanguage=en' \
--header 'Content-MD5: cQvTn30Hx7G2S4E/SQgjBw==' \
--header 'x-langboat-signature-method: HMAC-SHA256' \
--header 'x-langboat-signature-nonce: 92508' \
--header 'Authorization: tUGFmn3k3ty14o4d9iRBHq4INE******:f7s+9kLfIJWPB/uMSCySxDcjQLwdx7VJ92VqRsN/r+Y=' \
--header 'Date: Wed, 30 Nov 2022 02:51:03 GMT' \
--header 'Content-Type: application/json' \
--data-raw '{
"fileContent": "5L2g5aW977yM5LiW55WM",
"filename": "test.txt",
"fileType": "txt"
}'
# response:
{"code":0,"message":"success","requestId":"402cd89f6e5fecc600c496af2ee63d4a","data":{"docID":"448a2625-846a-4891-a48f-a43ed7117942"}}

下载翻译文档#

Query 参数#

QUERY参数是否必须描述
action文本翻译固定参数:translateDocDownload
docID文档ID, 前述提交待翻译文档返回的 docID

响应体#

成功的响应体是一个 JSON, 示例:

{
"code": 0,
"message": "success",
"requestId": "f82e17bdfda8dc8f98e42fc20eae3867",
"data": {
"domain": "general",
"sourceLanguage": "zh",
"targetLanguage": "en",
"filename": "test.txt",
"fileType": "txt",
"fileSize": 12,
"fileMD5": "",
"fileContent": "5L2g5aW977yM5LiW55WM"
}
}

data 字段说明

字段名类型描述
sourceLanguagestring原始语言
targetLanguagestring目标语言
filenamestring文档标题
fileTypestring文档类型, txt、docx
fileSizeinteger文档大小
fileMD5string文档MD5
fileContentstring翻译后文档的Base64编码

响应状态码、业务编码#

下面是可能的 HTTP 响应状态码、业务(错误)编码:

HTTP 状态码业务编码描述
2000文档翻译完成
20020001文档未翻译完成
20020002文档翻译失败
40010400请求异常
40110401鉴权失败,核对 accessKey 和 accessSecret 是否正确
40310403权限不足,查看是否开通服务;或QPS,字符数,次数超过限制
42210422参数错误,核对请求参数
50010500服务异常

请求示例#

# request:
curl --request GET 'https://open.langboat-test.cc?action=translateDocDownload&docID=448a2625-846a-4891-a48f-a43ed7117942' \
--header 'Content-MD5: 1B2M2Y8AsgTpgAmY7PhCfg==' \
--header 'x-langboat-signature-method: HMAC-SHA256' \
--header 'x-langboat-signature-nonce: 92508' \
--header 'Authorization: tUGFmn3k3ty14o4d9iRBHq4INE******:nhvdAy9711TuDHQ4kteFuarlscbtHHXclfb9LSW0Ao0=' \
--header 'Date: Wed, 30 Nov 2022 02:58:57 GMT' \
--header 'Content-Type: application/json'
# response
{
"code": 0,
"message": "success",
"requestId": "f82e17bdfda8dc8f98e42fc20eae3867",
"data": {
"domain": "general",
"sourceLanguage": "zh",
"targetLanguage": "en",
"filename": "test.txt",
"fileType": "txt",
"fileSize": 12,
"fileMD5": "",
"fileContent": "5L2g5aW977yM5LiW55WM"
}
}

示例代码#

  • Java (JDK-11)
api-example
├── pom.xml
├── src
│   ├── main
│   │   └── java
│   │   └── com.langboat.saas.example
│   │   ├── Examples.java
│   │   └── LangboatOpenClient.java

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.langboat.saas.example</groupId>
<artifactId>api-example</artifactId>
<version>1.0.0</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
<packaging>jar</packaging>
<name>api-example</name>
<properties>
<java.version>11</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.10</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.0</version>
</dependency>
</dependencies>
</project>

LangboatOpenClient.java

package com.langboat.saas.example;
import cn.hutool.core.util.URLUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.*;
public class LangboatOpenClient {
private final String accessKey;
private final String accessSecret;
private final String url;
public LangboatOpenClient(String accessKey, String accessSecret) {
this.accessKey = accessKey;
this.accessSecret = accessSecret;
this.url = "https://open.langboat.com";
}
public LangboatOpenClient(String accessKey, String accessSecret, String url) {
this.accessKey = accessKey;
this.accessSecret = accessSecret;
this.url = url;
}
/*
* 计算 MD5 + Base64
*/
private String MD5Base64(String s) {
if (s == null)
return null;
String encodeStr = "";
byte[] utfBytes = s.getBytes();
MessageDigest mdTemp;
try {
mdTemp = MessageDigest.getInstance("MD5");
mdTemp.update(utfBytes);
byte[] md5Bytes = mdTemp.digest();
encodeStr = Base64.getEncoder().encodeToString(md5Bytes);
} catch (Exception e) {
throw new Error("Failed to generate MD5 : " + e.getMessage());
}
return encodeStr;
}
/*
* 计算 HMAC-SHA256 + Base64 编码
*/
private String HMACSha256Base64(String data, String key) {
String result;
try {
SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(signingKey);
byte[] rawHmac = mac.doFinal(data.getBytes());
result = Base64.getEncoder().encodeToString(rawHmac);
} catch (Exception e) {
throw new Error("Failed to generate HMAC : " + e.getMessage());
}
return result;
}
/*
* 获取时间
*/
private String toGMTString(Date date) {
SimpleDateFormat df = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z", Locale.CHINA);
df.setTimeZone(new java.util.SimpleTimeZone(0, "GMT"));
return df.format(date);
}
/**
* 调用服务
* @param queries: query 参数
* @param data: request body 数据
* @return
*/
public Object inference(Map<String, String> queries,Map<String, Object> data) {
PrintWriter out = null;
BufferedReader in = null;
StringBuilder result = new StringBuilder();
try {
StringBuilder queriesStr = new StringBuilder();
queries.forEach((k, v) -> queriesStr.append("&").append(k).append("=").append(URLUtil.encode(v)));
queriesStr.setCharAt(0, '?');
URL openUrl = new URL(this.url +queriesStr);
String body = new ObjectMapper().writeValueAsString(data);
String method = "POST";
String accept = "application/json";
String contentType = "application/json";
String date = toGMTString(new Date());
// 1.对body做MD5+BASE64加密
String bodyMd5 = MD5Base64(body);
String nonce = "" + (int) (Math.random() * 65535);
String headerToSign = method + "\n" + accept + "\n" + bodyMd5 + "\n"
+ contentType + "\n" + date + "\n"
+ "HMAC-SHA256\n"
+ nonce + "\n";
// 2.计算 queryToSign
List<String> queriesList = new ArrayList<>();
queries.forEach((k, v) -> queriesList.add(k + "=" + v));
Collections.sort(queriesList);
String queryToSign = String.join("&", queriesList);
// 3.计算 stringToSign
String stringToSign = headerToSign + queryToSign;
// 4.计算 HMAC-SHA256 + Base64
String signature = HMACSha256Base64(stringToSign, this.accessSecret);
// 5.得到 authorization header 值
String authorization = this.accessKey + ":" + signature;
URLConnection conn = openUrl.openConnection();
conn.setRequestProperty("Accept", accept);
conn.setRequestProperty("Content-Type", contentType);
conn.setRequestProperty("Content-MD5", bodyMd5);
conn.setRequestProperty("Date", date);
conn.setRequestProperty("Authorization", authorization);
conn.setRequestProperty("x-langboat-signature-nonce", nonce);
conn.setRequestProperty("x-langboat-signature-method", "HMAC-SHA256");
// POST
conn.setDoOutput(true);
conn.setDoInput(true);
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(body);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
InputStream is;
HttpURLConnection httpConn = (HttpURLConnection) conn;
if (httpConn.getResponseCode() == 200) {
is = httpConn.getInputStream();
} else {
is = httpConn.getErrorStream();
}
in = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result.toString();
}
}

Examples.java

package com.langboat.saas.example;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.json.JSONUtil;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.Map;
/**
* API 调用示例
*/
public class Examples {
private final LangboatOpenClient client = new LangboatOpenClient("yourAccessKey", "yourAccessSecret");
/***
* 提交待翻译文档
* @param path 待翻译文档路径
* @throws IOException 文件异常
*/
public Object submitFileToTranslate(String path) throws IOException {
BufferedInputStream in = FileUtil.getInputStream(path);
String fileContent = Base64.getEncoder().encodeToString(in.readAllBytes());
Map<String, String> queries = Map.of(
"action", "translateDoc",
"domain", "general",
"sourceLanguage", "zh",
"targetLanguage", "en"
);
Map<String, Object> body = Map.of(
"fileContent", fileContent,
"filename", "test.txt",
"fileType", "txt"
);
return this.client.inference(queries, body);
}
/***
* 下载翻译后的文档, 解析base64编码的 fileContent 写入文件即可得到翻译后的文件
* @param docID 提交待翻译文档后得到的文档ID
* @param path 翻译后的文件保存的位置
*/
public void downloadTranslatedFile(String docID, String path) throws IOException {
Map<String, String> queries = Map.of(
"action", "translateDocDownload",
"docID", docID
);
String o2 = (String) this.client.inference(queries, null);
Map<String, Object> resp = JSONUtil.parseObj(o2);
Map<String, Object> data = BeanUtil.beanToMap(resp.get("data"));
String content = (String) data.get("fileContent");
String filename = (String) data.get("filename");
BufferedOutputStream out = FileUtil.getOutputStream(path + filename);
out.write(Base64.getDecoder().decode(content));
out.flush();
}
public static void main(String[] args) throws IOException {
Examples examples = new Examples();
Object res = examples.submitFileToTranslate("~/test.txt");
System.out.println(res);
examples.downloadTranslatedFile("628ad432-dac5-453c-92c6-31cd497852cb", "~/");
}
}

Python (>=3.6)#

# -*- coding: utf-8 -*-
import base64
import datetime
import hashlib
import hmac
import json
import random
import requests
class LangboatOpenClient:
"""澜舟开放平台客户端"""
def __init__(self,
access_key: str,
access_secret: str,
url: str = "https://open.langboat.com"):
self.access_key = access_key
self.access_secret = access_secret
self.url = url
def _build_header(self, query: dict, data: dict) -> dict:
accept = "application/json"
# 1. body MD5 加密
content_md5 = base64.b64encode(
hashlib.md5(
json.dumps(data).encode("utf-8")
).digest()
).decode()
content_type = "application/json"
gmt_format = '%a, %d %b %Y %H:%M:%S GMT'
date = datetime.datetime.utcnow().strftime(gmt_format)
signature_method = "HMAC-SHA256"
signature_nonce = str(random.randint(0, 65535))
header_string = f"POST\n{accept}\n{content_md5}\n{content_type}\n" \
f"{date}\n{signature_method}\n{signature_nonce}\n"
# 2. 计算 queryToSign
queries_str = []
for k, v in sorted(query.items(), key=lambda item: item[0]):
if isinstance(v, list):
for i in v:
queries_str.append(f"{k}={i}")
else:
queries_str.append(f"{k}={v}")
queries_string = '&'.join(queries_str)
# 3.计算 stringToSign
sign_string = header_string + queries_string
# 4.计算 HMAC-SHA256 + Base64
secret_bytes = self.access_secret.encode("utf-8")
# 5.计算签名
signature = base64.b64encode(
hmac.new(secret_bytes, sign_string.encode("utf-8"), hashlib.sha256).digest()
).decode()
res = {
"Content-Type": content_type,
"Content-MD5": content_md5,
"Date": date,
"Accept": accept,
"X-Langboat-Signature-Method": signature_method,
"X-Langboat-Signature-Nonce": signature_nonce,
"Authorization": f"{self.access_key}:{signature}"
}
return res
def inference(self, queries: dict, data: dict) -> (int, dict):
"""
服务调用
:param queries: query 参数
:param data: request body 数据
:return: response status, response body to json
"""
headers = self._build_header(queries, data)
response = requests.post(url=self.url, headers=headers, params=queries, json=data)
return response.status_code, response.json()
if __name__ == '__main__':
_access_key = '<Your access_key>'
_access_secret = '<Your access_secret>'
client = LangboatOpenClient(
access_key=_access_key,
access_secret=_access_secret
)
# 读取待翻译文档 text.txt(内容:"你好,世界")
with open("test.txt", "rb") as f:
content = base64.standard_b64encode(f.read())
# 获取文件的 base64 编码字符串
file_content = str(content, "utf-8")
# 提交待翻译文档
_queries = {
"action": "translateDoc",
"domain": "general",
"sourceLanguage": "zh",
"targetLanguage": "en"
}
_data = {
"fileContent": file_content,
"filename": "test.txt",
"fileType": "txt"
}
status_code, result = client.inference(_queries, _data)
print("response status:", status_code)
print("response json:", json.dumps(result, ensure_ascii=False, indent=2))
# 下载翻译完成的文档
status_code, result = client.inference({
"action": "translateDocDownload",
"docID": "54f60c11-6254-467a-8098-d806a1ad12ba", # 上面提交待翻译文档后返回的 docID
}, {})
print("response status:", status_code)
print("response json:", json.dumps(result, ensure_ascii=False, indent=2))
# 查看翻译后的文档内容
print(base64.b64decode(result['data']['fileContent']))
# 保存至文件 result.txt
with open("result.txt", 'wb') as f:
f.write(base64.b64decode(result['data']['fileContent']))

Go (>=1.14)#

package main
import (
"crypto/hmac"
"crypto/md5"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"math/rand"
"net/http"
"net/url"
"sort"
"strings"
"time"
)
func main() {
client := OpenClient{
baseURL: "https://open.langboat.com",
accessKey: "Your_Access_Key",
accessSecret: "Your_Access_Secret",
}
// 提交待翻译文档
queries := map[string]string{
"action": "translateDoc",
"domain": "general",
"sourceLanguage": "zh",
"targetLanguage": "en",
}
// 读取文档获取 base64 编码字符串
filename := "./test.docx"
content, _ := ioutil.ReadFile(filename)
encodedMessage := base64.StdEncoding.EncodeToString(content)
data := map[string]interface{}{
"fileContent": encodedMessage,
"filename": "test.docx",
"fileType": "docx",
}
resp := client.Inference(queries, data)
response, ok := resp.(*http.Response)
if !ok {
log.Fatal("fail to convert response")
}
body, err := ioutil.ReadAll(response.Body)
if err != nil {
log.Fatal("fail to read response body")
}
log.Println(string(body))
// 下载翻译后的文档
queries = map[string]string{
"action": "translateDocDownload",
"docID": "54f60c11-6254-467a-8098-d806a1ad12ba",
}
resp = client.Inference(queries, nil)
response, ok = resp.(*http.Response)
if !ok {
log.Fatal("fail to convert response")
}
body, err = ioutil.ReadAll(response.Body)
if err != nil {
log.Fatal("fail to read response body")
}
// 读取正文内容
type RetData struct {
SourceLanguage string `json:"source_language"` // 原始语言
TargetLanguage string `json:"target_language"` // 目标语言
Filename string `json:"file_name"` // 文档标题
FileType string `json:"file_type"` // 文档类型
FileSize int32 `json:"file_size"` // 文档大小
FileMD5 string `json:"file_md5"` // 文档MD5
FileContent string `json:"file_content"` // 文档的Base64编码
}
type DownloadResp struct {
Code int32 `json:"code"`
Message string `json:"message"`
RequestID string `json:"requestId"`
Data RetData `json:"data"`
}
var ret DownloadResp
_ = json.Unmarshal(body, &ret)
fileContent, _ := base64.StdEncoding.DecodeString(ret.Data.FileContent)
// 翻译结果写入文件
_ = ioutil.WriteFile("./"+ret.Data.Filename, fileContent, 0777)
}
type OpenClient struct {
baseURL string
accessKey string
accessSecret string
}
// Inference 调用服务。queries: query 参数;data: request body 数据
func (c *OpenClient) Inference(queries map[string]string, data map[string]interface{}) interface{} {
var queriesStr = ""
var first = true
for k, v := range queries {
if first {
queriesStr += "?" + k + "=" + url.QueryEscape(v)
first = false
} else {
queriesStr += "&" + k + "=" + url.QueryEscape(v)
}
}
dataJson, err := json.Marshal(data)
if err != nil {
log.Fatal(err.Error())
}
targetURL := c.baseURL + queriesStr
client := &http.Client{
Timeout: 15 * time.Second,
}
// 构造header
var (
payload = strings.NewReader(string(dataJson))
date = time.Now().UTC().Format(http.TimeFormat)
nonce = fmt.Sprint(10000 + rand.Intn(89999))
)
// 签名
signParam := SignParam{
Body: string(dataJson),
Query: queriesStr[1:],
DateGMT: date,
Nonce: nonce,
}
contentMD5, signature := GenSignature(signParam, c.accessSecret)
// 设置header
headers := map[string]string{
"Authorization": c.accessKey + ":" + signature,
"Content-Type": "application/json",
"Accept": "application/json",
"Date": date,
"Content-MD5": contentMD5,
"x-langboat-signature-method": "HMAC-SHA256",
"x-langboat-signature-nonce": nonce,
}
req, _ := http.NewRequest("POST", targetURL, payload)
for k, v := range headers {
req.Header.Add(k, v)
}
resp, err := client.Do(req)
if err != nil {
log.Println(err.Error())
}
return resp
}
// SignParam 生成签名需要的参数
type SignParam struct {
Body string // body数据
Query string // 原始query
DateGMT string // GTM时间
Nonce string // 随机数
}
func getMD5(str string) []byte {
h := md5.New()
h.Write([]byte(str))
return h.Sum(nil)
}
func hmacSha256(data string, secret string) []byte {
h := hmac.New(sha256.New, []byte(secret))
h.Write([]byte(data))
return h.Sum(nil)
}
func resortQuery(src string) string {
queries, _ := url.ParseQuery(src)
keys := make([]string, 0)
for k := range queries {
keys = append(keys, k)
}
sort.Strings(keys)
newQuery := url.Values{}
for _, k := range keys {
for _, value := range queries[k] {
newQuery.Add(k, value)
}
}
return newQuery.Encode()
}
// GenSignature 生成签名
func GenSignature(src SignParam, apiSecret string) (string, string) {
// 计算body的md5值
md5str := getMD5(src.Body)
// base64后得到contentMD5
contentMD5 := base64.StdEncoding.EncodeToString(md5str)
// query解析,并按照字典序重新排列
query := resortQuery(src.Query)
query, _ = url.QueryUnescape(query)
// 需要做签名的字符串结构
stringToSign := `POST
application/json
%s
application/json
%s
HMAC-SHA256
%s
%s`
stringToSign = fmt.Sprintf(stringToSign, contentMD5, src.DateGMT, src.Nonce, query)
hmac256 := hmacSha256(stringToSign, apiSecret)
signature := base64.StdEncoding.EncodeToString(hmac256)
return contentMD5, signature
}

产品服务

关于我们

孟子社区

最新动态

加入澜舟

商务合作邮箱

公司地址

北京市海淀区北四环西路(街)52 号方正国际大厦 16 层 1603


gongan京公网安备 11010802035393号京ICP备 2021021087号

经营许可证编号:合字 B2-20220333

大模型备案号:Beijing-MengZiGPT-20231205


合作:

bd@langboat.com

地址:

北京市海淀区北四环西路(街)52 号方正国际大厦 16 层 1603

公众号:

ewm

support
business