云修美型技术
该文档指引接入美图云修美型 API 中的美型技术服务,需先申请接口权限后方可接入使用,接口的接入通过 HTTP 异步调用的形式接入。美图云修 API 提供的服务均为异步接口,目前提供了 2 种形式来获取结果:消息通知回调、结果查询
1. 公共参数
权限
使用前需申请 AccessKey 和 SecretKey,并按照开放平台接口签名完成请求签名。
请求头
| 名称 | 类型 | 必填 | 描述 |
|---|---|---|---|
| Content-Type | string | 是 | 固定值:"application/json" |
请求方法
POST
2. 接口列表
1. 预设 ID 接入
请求地址: https://openapi.meitu.com/yunxiu_api/openapi/beauty_shape_async
请求方法: POST
请求头:
| 名称 | 类型 | 必填 | 描述 |
|---|---|---|---|
| Content-Type | string | 是 | 固定值:"application/json" |
请求参数(Body参数):
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| media_code | string | 是 | 预设 ID(什么是预设ID?) | MTyunxiu163aa58942 |
| media_data | string | 是 | 原图图片地址(不支持base64,只支持url) | https://beauty-public.zone1.meitudata.com/Marvel/1680141903114.jpg |
| repost_url | string | 否 | 结果回调地址,接入侧提供 | https://httpbin.org/ |
请求示例:
{
"media_code": "MTyunxiu",
"media_data": "https://beauty-public.zone1.meitudata.com/Marvel/1680141903114.jpg",
"repost_url": "https://httpbin.org/"
}响应参数:
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| code | int | 是 | 业务状态码 | 0 |
| data | struct | 是 | 结果数据 | { "msg_id": "8547e55f-9492-40a9-ba0d-7041b717ee5a" } |
| message | string | 否 | 提示信息 | success |
| request_id | string | 是 | 请求ID | 30c2194d-049b-4f69-95f8-0e9b440df2eb |
响应示例:
{
"code": 0,
"data": {
"msg_id": "8547e55f-9492-40a9-ba0d-7041b717ee5a"
},
"message": "",
"request_id": "30c2194d-049b-4f69-95f8-0e9b440df2eb"
}2.2 原始参数接入
请求地址: https://openapi.meitu.com/yunxiu_api/openapi/beauty_shape_async
请求方法: POST
请求参数(Body参数):
- media_info_list 参数结构
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| media_data | string | 是 | 原图图片地址(不支持base64,只支持url) | https://beauty-public.zone1.meitudata.com/Marvel/1680141903114.jpg |
| media_extra | struct | 否 | 资源描述额外信息 | {} |
| media_profiles | struct | 是 | 图片地址的资源描述 | 固定值{"media_data_type":"url","media_data_describe": "src"} |
[
{
"media_data": "https://beauty-public.zone1.meitudata.com/Marvel/1680141903114.jpg",
"media_extra": {},
"media_profiles": {
"media_data_type": "url",
"media_data_describe": "src"
}
}
]- parameter 参数结构:
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| all_params | struct | 是 | 图片处理参数 | 查看下文 |
| repost_url | string | 否 | 结果回调地址,接入侧提供 | https://httpbin.org/ |
| rsp_mask_version | int | 是 | - | 固定值500 |
| preview_size | int | 是 | - | 固定值3000 |
| people_type | array | 是 | 自定义年龄性别属性的数组顺序 | 查看下文 |
| output | struct | 是 | 输出结构 | 查看下文 |
- filter 参数结构:
| 名称 | 类型 | 是否必填 | 描述 | 范围 | 示例值 |
|---|---|---|---|---|---|
| filter_id | string | 否 | 滤镜ID | | | |
| filters_lut_alpha | int | 否 | 程度值 | 0~100 | 默认值50 |
| filter_is_black | int | 否 | | |
- blush、eyesocket等数组中对象结构:
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| id | string | 是 | 效果名称,默认值空 | "luozhuang" |
| color | string | 是 | 颜色值,rgba格式,默认值 0;0;0;0 | "" |
| alpha | int | 是 | 效果程度,默认值 0 | 50 |
- people_type 参数结构:
该字段用来定义图片中人物性别和年龄的对应关系,目前支持设置 5 种类型的人物性别。
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| age | list | 是 | 定义该属性的年龄范围 | [50, 100] |
| gender | int | 是 | 性别:1男 0女 | |
| key | string | 是 | 性别属性 | oldman |
| name | string | 否 | 性别属性名称 | 老 |
对于参数支持性别和年龄属性的,那么他的数据结构是一个 array,这个 array 总共有 5 个元素,分别对应 people_type 中的 5 种性别/年龄的定义,比如参数值:
beauty_belly_alpha: [10, 20, 30, 40, 50]然后 people_type 的定义顺序为(注:people_type数组每一个元素的结构是一个对象,这里用字符串是为了方便阅读,具体的数据结构参考推荐配置):
["man", "woman", "child", "oldwoman", "oldman"]那么表示 beauty_belly_alpha 对应会生效为:
{
"man": 10,
"woman": 20,
"child": 30,
"oldwoman": 40,
"oldman": 50
}推荐配置参数:
[
{
"age":[
15,
49
],
"gender":1,
"key":"man",
"name":"男"
},
{
"age":[
15,
49
],
"gender":0,
"key":"woman",
"name":"女"
},
{
"age":[
0,
14
],
"gender":0,
"key":"child",
"name":"儿童"
},
{
"age":[
50,
100
],
"gender":0,
"key":"oldwoman",
"name":"老年女"
},
{
"age":[
50,
100
],
"gender":1,
"key":"oldman",
"name":"老年男"
}
]- output 参数结构:
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| format | string | 是 | 输出格式,支持jpg和png | jpg |
| preview_size | string | 是 | 原图分割尺寸,推荐3000 | 3000 |
| qualityKey | int | 是 | 输出图质量,范围1~13,数值越大对应的画质越高;默认值12,对应画质99 | 12 |
| resize_height | int | 是 | 输出图尺寸(高),0表示原图输出,默认0,保留字段暂不支持配置 | 0 |
| resize_width | int | 是 | 输出图尺寸(宽),0表示原图输出,默认0,保留字段暂不支持配置 | 0 |
| water_mark | int | 是 | 是否水印,0无水印 1有水印 | 0 |
| file_size_limit | array | 否 | 输出图片大小范围,以示例值来说最小不超过原图的0.8,最大不超过原图的1.3 | [0.8, 1.3] |
- all_params 参数结构:
| 客户端模块 | 客户端参数名 | 算法参数 | 类型 | 是否必填 | 范围 | 示例值 |
|---|---|---|---|---|---|---|
| 全身美型高阶版 | 美型(多人液化) | multibody_beauty | array | 是 | 0~150 | 默认值 0 |
| 全身美型基础版 | 丰胸 | chest_enlarge | int | 是 | 0~100 | 默认值 0 |
| 全身美型基础版 | 美胯 | slim_hip | int | 是 | -100~100 | 默认值 0 |
| 全身美型基础版 | 瘦身 | slim | int | 是 | 0~100 | 默认值 0 |
| 全身美型基础版 | 瘦手臂 | slim_hand | int | 是 | 0~100 | 默认值 0 |
| 全身美型基础版 | 瘦腿 | slim_leg | int | 是 | 0~100 | 默认值 0 |
| 全身美型基础版 | 瘦腰 | slim_waist | int | 是 | 0~100 | 默认值 0 |
| 全身美型基础版 | 小头 | shrink_head | int | 是 | 0~100 | 默认值 0 |
| 全身美型基础版 | 长腿 | lengthen | int | 是 | 0~100 | 默认值 0 |
请求实例:
{
"parameter": {
"repost_url": "https://httpbin.org/",
"all_params": {
"chest_enlarge": 30,
"slim_hip": 15,
"slim": 23,
"slim_hand": 55,
"slim_leg": 40,
"slim_waist": 38,
"shrink_head": 30,
"lengthen": 98
},
"preview_size": 3000,
"people_type": [
{
"key": "man",
"gender": 1,
"name": "男",
"age": [
15,
49
]
},
{
"key": "woman",
"gender": 0,
"name": "女",
"age": [
15,
49
]
},
{
"key": "child",
"gender": 0,
"name": "儿童",
"age": [
0,
14
]
},
{
"key": "oldwoman",
"gender": 0,
"name": "老",
"age": [
50,
100
]
},
{
"key": "oldman",
"gender": 1,
"name": "老",
"age": [
50,
100
]
}
],
"output": {
"format": "jpg",
"preview_size": 3000,
"qualityKey": 12,
"resize_height": 0,
"resize_width": 0,
"water_mark": 0,
"file_size_limit": [
0,
0
]
}
},
"media_info_list": [
{
"media_data": "https://beauty-public.zone1.meitudata.com/Marvel/1680141903114.jpg",
"media_extra": {},
"media_profiles": {
"media_data_type": "url",
"media_data_describe": "src"
}
}
]
}3. 结果查询
1. 消息通知回调
当异步的任务处理完成后,会通过业务侧请求中的 repost_url 参数来回调通知。业务侧在处理完成后,需响应一个状态码为 200 的响应,响应体不做要求。
注意1:回调请求只会回调一次,业务方需做好服务保障,如没有接收到回调请求,可以通过主动查询来获取结果。
注意2: 同样的通知可能会多次回调给业务方,业务方的系统必须能够正确处理重复的通知。
注意3:处理回调的时候切记要判断回调内容是否正确后,再进行后续的业务逻辑处理,避免损失。
**通知地址:**业务方提供的 repost_url 参数
**通知请求方法:**POST
**请求头:**Content-Type:application/json
请求参数(Body参数):
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| code | int | 是 | 业务状态码 | 0 |
| data | struct | 是 | 结果数据 | 查看 |
| message | string | 否 | 提示信息 | success |
- data 字段结构:
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| msg_id | string | 是 | 异步任务ID | 838b1d4a-ba79-44bd-b496-8a5a3b14097e |
| media_data | string | 是 | 处理好的效果图地址 | https://beauty-public.zone1.meitudata.com/Marvel/1680141903114.jpg |
请求示例:
{
"code": 0,
"data": {
"msg_id": "8547e55f-9492-40a9-ba0d-7041b717ee5a",
"media_data": "https://obs-open-platform-photo.obs.cn-north-4.myhuaweicloud.com/mtopen/KxZo7A5mPWTP3FVhVThFu9VlA0s6p59c/MTY5MzE5MTYwMA==/c69a44d6-bace-446e-51e1-2dcd91a606ed.jpeg"
},
"message": "success",
"request_id": "838b1d4a-ba79-44bd-b496-8a5a3b14097e"
}3.2 轮训请求查询
注意:异步任务的结果只保存 12 个小时,请及时查询并转存效果图图片,过期后该异步任务 ID 将无法查询到结果。请求之后切记要解析响应的 Body 来做结果判断。
请求地址: https://openapi.meitu.com/yunxiu_api/openapi/query
请求方法: POST
请求参数(Body参数):
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| msg_id | string | 是 | 异步任务ID | 6aca960e-6669-4f39-805e-9bc69705b82d |
请求示例:
{
"msg_id": "6aca960e-6669-4f39-805e-9bc69705b82d"
}响应参数:
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| code | int | 是 | 业务状态码 | 0 |
| data | struct | 是 | 结果数据 | 参考下文示例 |
| message | string | 否 | 提示信息 | success |
| request_id | string | 是 | 请求ID | 838b1d4a-ba79-44bd-b496-8a5a3b14097e |
data 字段结构:
| 名称 | 类型 | 是否必填 | 描述 | 示例值 |
|---|---|---|---|---|
| msg_id | string | 是 | 异步任务ID | 838b1d4a-ba79-44bd-b496-8a5a3b14097e |
| media_data | string | 是 | 处理好的效果图地址 | https://beauty-public.zone1.meitudata.com/Marvel/1680141903114.jpg |
响应示例:
{
"code": 0,
"data": {
"msg_id": "8547e55f-9492-40a9-ba0d-7041b717ee5a",
"media_data": "https://obs-open-platform-photo.obs.cn-north-4.myhuaweicloud.com/mtopen/KxZo7A5mPWTP3FVhVThFu9VlA0s6p59c/MTY5MzE5MTYwMA==/c69a44d6-bace-446e-51e1-2dcd91a606ed.jpeg"
},
"message": "success",
"request_id": "838b1d4a-ba79-44bd-b496-8a5a3b14097e"
}4. 错误码
| 错误码 | 错误信息 | 描述 |
|---|---|---|
| 0 | SUCCESS | 请求成功 |
| 29901 | NOT_RESULT | 图片还在处理中,结果还没出来 |
| 29902 | RECORD_NOT_FOUND | 异步任务 ID 已过期 |
| 90002 | GATEWAY_AUTHORIZED_ERROR | 接口未授权/密钥错误 |
| 11201 | UNKNOW ERROR | 用户图片地址下载失败 |
| 20001 | UNKNOW ERROR | 图片处理失败 |
SDK 调用示例
安装对应语言的签名 SDK。Python 还需安装 requests,PHP 需将 signer.php 放在示例同目录,Java 文件名为 Main.java。
填入 AK、SK、预设 ID 和图片地址即可提交任务。查询时使用提交返回的 data.msg_id。
Python
import json
import requests
from sign_sdk import sign
def api_call_example():
key = "your_access_key"
secret = "your_secret_key"
url = "https://openapi.meitu.com/yunxiu_api/openapi/beauty_shape_async"
method = "POST"
headers = {
"Content-Type": "application/json",
sign.HeaderHost: "openapi.meitu.com",
}
payload = {"media_code": "YOUR_PRESET_ID", "media_data": "https://example.com/portrait.jpg"}
body = json.dumps(payload, ensure_ascii=False)
signer = sign.Signer(key, secret)
signed_request = signer.sign(url, method, headers, body)
with requests.Session() as session:
response = session.send(signed_request, timeout=60)
print("Status:", response.status_code)
print("Response:", response.text)
if __name__ == "__main__":
api_call_example()Go
package main
import (
"fmt"
"github.com/mtlab/api/signer"
"io"
"net/http"
"time"
)
func main() {
key := "your_access_key"
secret := "your_secret_key"
signObj := signer.NewSigner(key, secret)
url := "https://openapi.meitu.com/yunxiu_api/openapi/beauty_shape_async"
headers := make(http.Header)
headers.Set(signer.HeaderHost, "openapi.meitu.com")
headers.Set("Content-Type", "application/json")
body := `{"media_code":"YOUR_PRESET_ID","media_data":"https://example.com/portrait.jpg"}`
req, err := signObj.Sign(url, http.MethodPost, headers, body)
if err != nil {
fmt.Println("Failed to sign request:", err)
return
}
client := &http.Client{Timeout: 60 * time.Second}
resp, err := client.Do(req)
if err != nil {
fmt.Println("Failed to send request:", err)
return
}
defer resp.Body.Close()
responseBody, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Failed to read response:", err)
return
}
fmt.Println("Status:", resp.StatusCode)
fmt.Println("Response:", string(responseBody))
}PHP
<?php
require_once __DIR__ . '/signer.php';
$key = 'your_access_key';
$secret = 'your_secret_key';
$url = 'https://openapi.meitu.com/yunxiu_api/openapi/beauty_shape_async';
$headers = [
'Content-Type' => 'application/json',
'Host' => 'openapi.meitu.com',
];
$payload = ['media_code' => 'YOUR_PRESET_ID', 'media_data' => 'https://example.com/portrait.jpg'];
$body = json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR);
$signer = new Signer($key, $secret);
$curl = $signer->sign($url, 'POST', $headers, $body);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_TIMEOUT, 60);
$response = curl_exec($curl);
if ($response === false) {
echo 'Error: ' . curl_error($curl);
} else {
echo 'Status: ' . curl_getinfo($curl, CURLINFO_HTTP_CODE) . PHP_EOL;
echo 'Response: ' . $response . PHP_EOL;
}
curl_close($curl);Java
import com.meitu.openai.common.Signer;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) throws Exception {
Signer signer = new Signer("your_access_key", "your_secret_key");
String url = "https://openapi.meitu.com/yunxiu_api/openapi/beauty_shape_async";
String method = "POST";
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
headers.put(Signer.HeaderHost, "openapi.meitu.com");
String body = "{\"media_code\": \"YOUR_PRESET_ID\", \"media_data\": \"https://example.com/portrait.jpg\"}";
Map<String, String> signedHeaders = signer.sign(url, method, headers, body);
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
try {
connection.setRequestMethod(method);
connection.setConnectTimeout(10000);
connection.setReadTimeout(60000);
connection.setInstanceFollowRedirects(false);
for (Map.Entry<String, String> header : signedHeaders.entrySet()) {
connection.setRequestProperty(header.getKey(), header.getValue());
}
connection.setDoOutput(true);
try (OutputStream output = connection.getOutputStream()) {
output.write(body.getBytes(StandardCharsets.UTF_8));
}
int status = connection.getResponseCode();
InputStream stream = status >= 400
? connection.getErrorStream()
: connection.getInputStream();
System.out.println("Status: " + status);
if (stream != null) {
try (InputStream input = stream;
ByteArrayOutputStream output = new ByteArrayOutputStream()) {
byte[] buffer = new byte[4096];
int length;
while ((length = input.read(buffer)) != -1) {
output.write(buffer, 0, length);
}
System.out.println("Response: " + output.toString("UTF-8"));
}
}
} finally {
connection.disconnect();
}
}
}原始参数提交示例
将上文的完整原始请求体保存为 params.json,替换图片地址和处理参数。
Python
import json
import requests
from sign_sdk import sign
def api_call_example():
key = "your_access_key"
secret = "your_secret_key"
url = "https://openapi.meitu.com/yunxiu_api/openapi/beauty_shape_async"
method = "POST"
headers = {
"Content-Type": "application/json",
sign.HeaderHost: "openapi.meitu.com",
}
with open("params.json", encoding="utf-8") as source:
body = source.read()
signer = sign.Signer(key, secret)
signed_request = signer.sign(url, method, headers, body)
with requests.Session() as session:
response = session.send(signed_request, timeout=60)
print("Status:", response.status_code)
print("Response:", response.text)
if __name__ == "__main__":
api_call_example()Go
package main
import (
"fmt"
"github.com/mtlab/api/signer"
"io"
"net/http"
"os"
"time"
)
func main() {
key := "your_access_key"
secret := "your_secret_key"
signObj := signer.NewSigner(key, secret)
url := "https://openapi.meitu.com/yunxiu_api/openapi/beauty_shape_async"
headers := make(http.Header)
headers.Set(signer.HeaderHost, "openapi.meitu.com")
headers.Set("Content-Type", "application/json")
data, err := os.ReadFile("params.json")
if err != nil { panic(err) }
body := string(data)
req, err := signObj.Sign(url, http.MethodPost, headers, body)
if err != nil {
fmt.Println("Failed to sign request:", err)
return
}
client := &http.Client{Timeout: 60 * time.Second}
resp, err := client.Do(req)
if err != nil {
fmt.Println("Failed to send request:", err)
return
}
defer resp.Body.Close()
responseBody, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Failed to read response:", err)
return
}
fmt.Println("Status:", resp.StatusCode)
fmt.Println("Response:", string(responseBody))
}PHP
<?php
require_once __DIR__ . '/signer.php';
$key = 'your_access_key';
$secret = 'your_secret_key';
$url = 'https://openapi.meitu.com/yunxiu_api/openapi/beauty_shape_async';
$headers = [
'Content-Type' => 'application/json',
'Host' => 'openapi.meitu.com',
];
$body = file_get_contents(__DIR__ . '/params.json');
if ($body === false) { throw new RuntimeException('Cannot read params.json'); }
$signer = new Signer($key, $secret);
$curl = $signer->sign($url, 'POST', $headers, $body);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_TIMEOUT, 60);
$response = curl_exec($curl);
if ($response === false) {
echo 'Error: ' . curl_error($curl);
} else {
echo 'Status: ' . curl_getinfo($curl, CURLINFO_HTTP_CODE) . PHP_EOL;
echo 'Response: ' . $response . PHP_EOL;
}
curl_close($curl);Java
import com.meitu.openai.common.Signer;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) throws Exception {
Signer signer = new Signer("your_access_key", "your_secret_key");
String url = "https://openapi.meitu.com/yunxiu_api/openapi/beauty_shape_async";
String method = "POST";
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
headers.put(Signer.HeaderHost, "openapi.meitu.com");
String body = new String(java.nio.file.Files.readAllBytes(java.nio.file.Paths.get("params.json")), StandardCharsets.UTF_8);
Map<String, String> signedHeaders = signer.sign(url, method, headers, body);
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
try {
connection.setRequestMethod(method);
connection.setConnectTimeout(10000);
connection.setReadTimeout(60000);
connection.setInstanceFollowRedirects(false);
for (Map.Entry<String, String> header : signedHeaders.entrySet()) {
connection.setRequestProperty(header.getKey(), header.getValue());
}
connection.setDoOutput(true);
try (OutputStream output = connection.getOutputStream()) {
output.write(body.getBytes(StandardCharsets.UTF_8));
}
int status = connection.getResponseCode();
InputStream stream = status >= 400
? connection.getErrorStream()
: connection.getInputStream();
System.out.println("Status: " + status);
if (stream != null) {
try (InputStream input = stream;
ByteArrayOutputStream output = new ByteArrayOutputStream()) {
byte[] buffer = new byte[4096];
int length;
while ((length = input.read(buffer)) != -1) {
output.write(buffer, 0, length);
}
System.out.println("Response: " + output.toString("UTF-8"));
}
}
} finally {
connection.disconnect();
}
}
}查询结果(Query)
将提交响应中的 data.msg_id 填入以下示例的 YOUR_MSG_ID,签名后发送 POST 请求查询结果。
Python
import json
import requests
from sign_sdk import sign
def api_call_example():
key = "your_access_key"
secret = "your_secret_key"
url = "https://openapi.meitu.com/yunxiu_api/openapi/query"
method = "POST"
headers = {
"Content-Type": "application/json",
sign.HeaderHost: "openapi.meitu.com",
}
payload = {"msg_id": "YOUR_MSG_ID"}
body = json.dumps(payload, ensure_ascii=False)
signer = sign.Signer(key, secret)
signed_request = signer.sign(url, method, headers, body)
with requests.Session() as session:
response = session.send(signed_request, timeout=60)
print("Status:", response.status_code)
print("Response:", response.text)
if __name__ == "__main__":
api_call_example()Go
package main
import (
"fmt"
"github.com/mtlab/api/signer"
"io"
"net/http"
"time"
)
func main() {
key := "your_access_key"
secret := "your_secret_key"
signObj := signer.NewSigner(key, secret)
url := "https://openapi.meitu.com/yunxiu_api/openapi/query"
headers := make(http.Header)
headers.Set(signer.HeaderHost, "openapi.meitu.com")
headers.Set("Content-Type", "application/json")
body := `{"msg_id":"YOUR_MSG_ID"}`
req, err := signObj.Sign(url, http.MethodPost, headers, body)
if err != nil {
fmt.Println("Failed to sign request:", err)
return
}
client := &http.Client{Timeout: 60 * time.Second}
resp, err := client.Do(req)
if err != nil {
fmt.Println("Failed to send request:", err)
return
}
defer resp.Body.Close()
responseBody, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Failed to read response:", err)
return
}
fmt.Println("Status:", resp.StatusCode)
fmt.Println("Response:", string(responseBody))
}PHP
<?php
require_once __DIR__ . '/signer.php';
$key = 'your_access_key';
$secret = 'your_secret_key';
$url = 'https://openapi.meitu.com/yunxiu_api/openapi/query';
$headers = [
'Content-Type' => 'application/json',
'Host' => 'openapi.meitu.com',
];
$payload = ['msg_id' => 'YOUR_MSG_ID'];
$body = json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR);
$signer = new Signer($key, $secret);
$curl = $signer->sign($url, 'POST', $headers, $body);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_TIMEOUT, 60);
$response = curl_exec($curl);
if ($response === false) {
echo 'Error: ' . curl_error($curl);
} else {
echo 'Status: ' . curl_getinfo($curl, CURLINFO_HTTP_CODE) . PHP_EOL;
echo 'Response: ' . $response . PHP_EOL;
}
curl_close($curl);Java
import com.meitu.openai.common.Signer;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) throws Exception {
Signer signer = new Signer("your_access_key", "your_secret_key");
String url = "https://openapi.meitu.com/yunxiu_api/openapi/query";
String method = "POST";
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
headers.put(Signer.HeaderHost, "openapi.meitu.com");
String body = "{\"msg_id\":\"YOUR_MSG_ID\"}";
Map<String, String> signedHeaders = signer.sign(url, method, headers, body);
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
try {
connection.setRequestMethod(method);
connection.setConnectTimeout(10000);
connection.setReadTimeout(60000);
connection.setInstanceFollowRedirects(false);
for (Map.Entry<String, String> header : signedHeaders.entrySet()) {
connection.setRequestProperty(header.getKey(), header.getValue());
}
connection.setDoOutput(true);
try (OutputStream output = connection.getOutputStream()) {
output.write(body.getBytes(StandardCharsets.UTF_8));
}
int status = connection.getResponseCode();
InputStream stream = status >= 400
? connection.getErrorStream()
: connection.getInputStream();
System.out.println("Status: " + status);
if (stream != null) {
try (InputStream input = stream;
ByteArrayOutputStream output = new ByteArrayOutputStream()) {
byte[] buffer = new byte[4096];
int length;
while ((length = input.read(buffer)) != -1) {
output.write(buffer, 0, length);
}
System.out.println("Response: " + output.toString("UTF-8"));
}
}
} finally {
connection.disconnect();
}
}
}