package com.volcengine.example.cv;
import com.alibaba.fastjson.JSONObject;
import com.google.common.io.ByteStreams;
import com.volcengine.helper.Utils;
import org.apache.commons.codec.binary.Hex;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
* Copyright (year) Beijing Volcano Engine Technology Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
private static final BitSet URLENCODER = new BitSet(256);
private static final String CONST_ENCODE = "0123456789ABCDEF";
public static final Charset UTF_8 = StandardCharsets.UTF_8;
private final String region;
private final String service;
private final String schema;
private final String host;
private final String path;
private final String ak;
private final String sk;
for (i = 97; i <= 122; ++i) {
for (i = 65; i <= 90; ++i) {
for (i = 48; i <= 57; ++i) {
public static void main(String[] args) throws Exception {
String AccessKeyID = "AK*****";
String SecretAccessKey = "******==";
String endpoint = "visual.volcengineapi.com";
String path = "/"; // 路径,不包含 Query// 请求接口信息
String region = "cn-north-1";
String schema = "https";
Sign sign = new Sign(region, service, schema, endpoint, path, AccessKeyID, SecretAccessKey);
String action = "CVProcess";
String version = "2022-08-31";
JSONObject req=new JSONObject();
req.put("req_key","xxx");
ArrayList<String> imageUrls = new ArrayList<String>();
imageUrls.add("******");
req.put("image_urls",imageUrls);
req.put("prompt","******");
sign.doRequest("POST", new HashMap(), req.toJSONString().getBytes(), date, action, version);
public Sign(String region, String service, String schema, String host, String path, String ak, String sk) {
public void doRequest(String method, Map<String, String> queryList, byte[] body,
Date date, String action, String version) throws Exception {
String xContentSha256 = hashSHA256(body);
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
String xDate = sdf.format(date);
String shortXDate = xDate.substring(0, 8);
String contentType = "application/json";
String signHeader = "host;x-date;x-content-sha256;content-type";
SortedMap<String, String> realQueryList = new TreeMap<>(queryList);
realQueryList.put("Action", action);
realQueryList.put("Version", version);
StringBuilder querySB = new StringBuilder();
for (String key : realQueryList.keySet()) {
querySB.append(signStringEncoder(key)).append("=").append(signStringEncoder(realQueryList.get(key))).append("&");
querySB.deleteCharAt(querySB.length() - 1);
String canonicalStringBuilder = method + "\n" + path + "\n" + querySB + "\n" +
"x-date:" + xDate + "\n" +
"x-content-sha256:" + xContentSha256 + "\n" +
"content-type:" + contentType + "\n" +
System.out.println(canonicalStringBuilder);
String hashcanonicalString = hashSHA256(canonicalStringBuilder.getBytes());
String credentialScope = shortXDate + "/" + region + "/" + service + "/request";
String signString = "HMAC-SHA256" + "\n" + xDate + "\n" + credentialScope + "\n" + hashcanonicalString;
byte[] signKey = genSigningSecretKeyV4(sk, shortXDate, region, service);
// String signature = HexFormat.of().formatHex(hmacSHA256(signKey, signString));
String signature = Hex.encodeHexString(Utils.hmacSHA256(signKey, signString));
URL url = new URL(schema + "://" + host + path + "?" + querySB);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(method);
conn.setRequestProperty("Host", host);
conn.setRequestProperty("X-Date", xDate);
conn.setRequestProperty("X-Content-Sha256", xContentSha256);
conn.setRequestProperty("Content-Type", contentType);
conn.setRequestProperty("Authorization", "HMAC-SHA256" +
" Credential=" + ak + "/" + credentialScope +
", SignedHeaders=" + signHeader +
", Signature=" + signature);
if (!Objects.equals(conn.getRequestMethod(), "GET")) {
OutputStream os = conn.getOutputStream();
int responseCode = conn.getResponseCode();
if (responseCode == 200) {
is = conn.getInputStream();
is = conn.getErrorStream();
String responseBody = new String(ByteStreams.toByteArray(is));
System.out.println(responseCode);
System.out.println(responseBody);
private String signStringEncoder(String source) {
StringBuilder buf = new StringBuilder(source.length());
ByteBuffer bb = UTF_8.encode(source);
while (bb.hasRemaining()) {
if (URLENCODER.get(b)) {
char hex1 = CONST_ENCODE.charAt(b >> 4);
char hex2 = CONST_ENCODE.charAt(b & 15);
public static String hashSHA256(byte[] content) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256");
return Hex.encodeHexString(md.digest(content));
"Unable to compute hash while signing request: "
public static byte[] hmacSHA256(byte[] key, String content) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(key, "HmacSHA256"));
return mac.doFinal(content.getBytes());
"Unable to calculate a request signature: "
private byte[] genSigningSecretKeyV4(String secretKey, String date, String region, String service) throws Exception {
byte[] kDate = hmacSHA256((secretKey).getBytes(), date);
byte[] kRegion = hmacSHA256(kDate, region);
byte[] kService = hmacSHA256(kRegion, service);
return hmacSHA256(kService, "request");