This topic describes how to send HTTP requests to call Alibaba Cloud API operations in the resource-oriented architecture (ROA) style.
The request syntax and signature method V2 are discontinued. Use the request syntax and signature method V3.
HTTP request syntax
The following table describes the parameters that are included in a complete Alibaba Cloud API request.
Component | Required | Description | Example |
Protocol | Yes | The request protocol. You can view the protocols supported by the API in the API metadata. If the API supports both | https:// |
Endpoint | Yes | The endpoint of the Alibaba Cloud service API. Topics that list the endpoints of each Alibaba Cloud service are available. You can view the endpoints of a service in different regions in these topics. | bailian.cn-beijing.aliyuncs.com |
resource_URI_parameters | Yes | The URL of the operation. The URL contains the path of the API and the request parameters in the path and query components. | /{WorkspaceId}/datacenter/category |
RequestHeader | Yes | The request headers. In most cases, information such as the API version number, endpoint, and authentication information is included. For more information, see the Parameters for RequestHeader section of this topic. | Accept:application/json Authorization:acs YourAccessKeyId:s8ZMF/eAIvvPJwehLLha0bVNFJ0= Content-MD5:LP54yxk8n7KqF1PPgbJizw== Content-Type:application/json Date:Wed, 16 Apr 2025 03:44:46 GMT Host:bailian.cn-beijing.aliyuncs.com x-acs-signature-method:HMAC-SHA1 x-acs-signature-nonce:ef34aae7-7bd2-413d-a541-680cd2c48538 x-acs-signature-version:1.0 x-acs-version:2023-12-29 |
RequestBody | Yes | The operation-specific parameters in the request body. For more information, visit OpenAPI Explorer. | {"CategoryName":"test","CategoryType":"UNSTRUCTURED"} |
HTTPMethod | Yes | The request method of an ROA API. Valid values: PUT, POST, GET, and DELETE. You can view the request methods supported by the API in the API reference. | POST |
Parameters for RequestHeader
The following table describes the parameters that are included in a complete Alibaba Cloud API request.
Parameter | Type | Required | Description | Example |
Accept | String | No | The response format. If you do not specify this parameter, the response is in the XML format. To call an ROA-style API operation, set the value to | application/json |
Content-MD5 | String | No | The Base64-encoded 128-bit MD5 hash value of the request body. | LP54yxk8n7KqF1PPgbJizw== |
Date | String | Yes | The timestamp of the request. The timestamp is valid for 15 minutes. You must initiate the request within 15 minutes after the timestamp is generated. Specify the time in GMT in compliance with HTTP 1.1. Example: Tue 9 Apr 2019 07:35:29 GMT. | Wed, 16 Apr 2025 03:44:46 GMT |
Host | String | Yes | The endpoint of the Alibaba Cloud service API. For more information, see the HTTP request structure section of this topic. | bailian.cn-beijing.aliyuncs.com |
x-acs-signature-method | String | Yes if the request is non-anonymous | The encryption method of the signature string. Set the value to | HMAC-SHA1 |
x-acs-signature-nonce | String | Yes | A unique, random number used to prevent network replay attacks. To prevent replay attacks, we recommend that you use different numbers for different requests. | ef34aae7-7bd2-413d-a541-680cd2c48538 |
x-acs-signature-version | String | No | The signature version. Set the value to | 1.0 |
x-acs-version | String | Yes | The version of the API. You can obtain the API version in OpenAPI Explorer or in the API metadata. | 2023-12-29 |
Authorization | String | Yes if the request is non-anonymous | The authentication information that is used to verify the validity of the request. Specify the value in the The Signature parameter specifies the signature string of the request. For more information, see the Signature method section of this topic. | acs YourAccessKeyId:D9uFJAJgLL+dryjBfQK+YeqGtoY= |
Signature method
You must sign all HTTP and HTTPS API requests to ensure security. When a request reaches the Alibaba Cloud API gateway, the gateway recalculates the signature based on the request parameters and request header, and then compares the calculated signature with the signature in the request to verify the identity of the API caller. This mechanism ensures data integrity and security. This section describes how to calculate signatures.
All requests and responses are encoded in UTF-8.
Step 1: Construct a canonicalized header
Canonicalized headers are non-standard HTTP headers Non-standard HTTP headers are headers whose names are prefixed with x-acs- in the request. To construct canonicalized headers, perform the following steps:
Convert the request header names prefixed with
x-acs-in the request header to lowercase letters and sort them in ascending lexicographical order.Remove the leading and trailing spaces from the name and value of the request header.
Append the
\ndelimiter to the end of each header, including the last header, and concatenate all the headers.
Example:
x-acs-signature-method:HMAC-SHA1
x-acs-signature-nonce:ef34aae7-7bd2-413d-a541-680cd2c48538
x-acs-signature-version:1.0
x-acs-version:2023-12-29
Step 2: Construct a canonicalized resource
Canonicalized resources are the canonical descriptions of the resources that you want to access. You can perform the following steps to construct canonicalized resources:
Sort the parameters in the query string of the request by name in alphabetical order and concatenate the parameters by using ampersands (
&) to generate the sorted query string.Concatenate the requested resource path with the sorted query string by using a question mark (
?) to obtain canonicalized resources. The resource path is the part between the endpoint and the query string. The path includes the forward slash (/) following the endpoint but excludes the question mark (?) preceding the query string. If the request does not contain a query string, use the resource path as the canonicalized resource.
Example:
/llm-p2e4XXXXXXXXsvtn/datacenter/categoryStep 3: Construct a string-to-sign
Create a string-to-sign based on the following pseudocode:
String stringToSign =
HTTPMethod + "\n" +
Accept + "\n" +
ContentMD5 + "\n" +
ContentType + "\n" +
Date + "\n" +
CanonicalizedHeaders +
CanonicalizedResourceParameter | Description |
HTTPMethod | The HTTP method in uppercase letters, such as POST or GET. |
Accept | The value of the Accept header. Set the value to an empty string if this header does not exist. |
ContentMD5 | The value of the Content-MD5 header. Set the value to an empty string if this header does not exist. |
ContentType | The value of the Content-Type header. Set the value to an empty string if this header does not exist. Note The Multipurpose Internet Mail Extensions (MIME) type of the request body. |
Date | The value of the Date header. |
CanonicalizedHeaders | The canonicalized headers that are obtained from Step 1: Construct canonicalized headers of this topic. |
CanonicalizedResource | The canonicalized resources that are obtained from Step 2: Construct canonicalized resources of this topic. |
Example:
POST
application/json
LP54yxk8n7KqF1PPgbJizw==
application/json
Wed, 16 Apr 2025 03:44:46 GMT
x-acs-signature-method:HMAC-SHA1
x-acs-signature-nonce:ef34aae7-7bd2-413d-a541-680cd2c48538
x-acs-signature-version:1.0
x-acs-version:2023-12-29
/llm-p2e4XXXXXXXXsvtn/datacenter/categoryStep 4: Calculate the signature string
Calculate the hash-based message authentication code (HMAC) value of the string-to-sign by using the HMAC-SHA1 algorithm and encode the HMAC value into a signature string based on Base64 encoding rules. For more information about HMAC, see RFC 2104.
String signature = Base64(HMAC_SHA1(SigningKey, stringToSign))Set the SigningKey parameter to your AccessKey secret. For more information, see Create an AccessKey pair.
Example:
s8ZMF/eAIvvPJwehLLha0bVNFJ0=Step 5: Specify the Authorization header.
After you obtain the signature string, construct the value of the Authorization header based on the following code:
String Authorization = "acs " + AccessKeyId + ":" + signatureExample:
acs YourAccessKeyId:s8ZMF/eAIvvPJwehLLha0bVNFJ0=Step 6: Add the signature to the request and send the request.
POST https://bailian.cn-beijing.aliyuncs.com/llm-p2e4XXXXXXXXsvtn/datacenter/category HTTP/1.1
Accept:application/json
Authorization:acs YourAccessKeyId:r8Y9ZqVhTrYGl4nieqk7CW0Pwow=
Content-MD5:LP54yxk8n7KqF1PPgbJizw==
Content-Type:application/json
Date:Wed, 16 Apr 2025 06:47:10 GMT
Host:bailian.cn-beijing.aliyuncs.com
x-acs-signature-method:HMAC-SHA1
x-acs-signature-nonce:e3d8efa7-b1d8-42f3-9733-4fe2691e15dc
x-acs-signature-version:1.0
x-acs-version:2023-12-29
{"CategoryName":"test","CategoryType":"UNSTRUCTURED"}Signature examples
Java
In this example, the JDK 1.8 runtime environment is used. Adjust the parameters based on your business requirements.
To use the signature method in Java, you must add the following Maven dependencies to the pom.xml file:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.9.0</version>
</dependency>import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;
public class SignatureDemo {
public static class SignatureRequest {
private final String httpMethod;
private final String host;
private final String version;
private final String canonicalUri;
public TreeMap<String, String> headers = new TreeMap<>();
public TreeMap<String, Object> queryParams = new TreeMap<>();
public byte[] bodyByteArray;
public SignatureRequest(String httpMethod, String host, String version, String canonicalUri) {
this.httpMethod = httpMethod;
this.host = host;
this.version = version;
this.canonicalUri = canonicalUri;
initHeaders();
}
private void initHeaders() {
headers.put("Host", host);
headers.put("x-acs-version", version);
headers.put("x-acs-signature-version", "1.0");
headers.put("Accept", "application/json");
headers.put("x-acs-signature-nonce", java.util.UUID.randomUUID().toString());
headers.put("Date", getGmtDate());
headers.put("x-acs-signature-method", "HMAC-SHA1");
}
private String getGmtDate() {
SimpleDateFormat gmtFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.ENGLISH);
gmtFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
return gmtFormat.format(new Date());
}
public void setBody(Map<String, String> body, ContentType contentType) {
Gson gson = (new GsonBuilder()).disableHtmlEscaping().create();
this.bodyByteArray = gson.toJson(body).getBytes(StandardCharsets.UTF_8);
headers.put("Content-MD5", md5Sum(this.bodyByteArray));
headers.put("Content-Type", contentType.getMimeType());
}
}
private static final String ACCESS_KEY_ID = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
private static final String ACCESS_KEY_SECRET = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
private static final String ALGORITHM_NAME = "HmacSHA1";
public static void main(String[] args) {
// Example 1: Send a POST request.
String method = "POST";
String host = "bailian.cn-beijing.aliyuncs.com";
String version = "2023-12-29";
String canonicalUri = "/llm-p2e4XXXXXXXXsvtn/datacenter/category";
SignatureRequest signatureRequest = new SignatureRequest(method, host, version, canonicalUri);
Map<String, String> body = new HashMap<>();
body.put("CategoryName", "test");
body.put("CategoryType", "UNSTRUCTURED");
System.out.println(new Gson().toJson(body));
signatureRequest.setBody(body, ContentType.APPLICATION_JSON);
/*// Example 2: Send a GET request.
String method = "GET";
String host = "bailian.cn-beijing.aliyuncs.com";
String version = "2023-12-29";
String canonicalUri = "/llm-p2e4XXXXXXXXsvtn/datacenter/files";
SignatureRequest signatureRequest = new SignatureRequest(method, host, version, canonicalUri);
signatureRequest.queryParams.put("CategoryId", "cate_a946*********************_10045991");*/
/*// Example 3: Send a DELETE request.
String method = "DELETE";
String host = "bailian.cn-beijing.aliyuncs.com";
String version = "2023-12-29";
String canonicalUri = "/llm-p2e4XXXXXXXXsvtn/datacenter/category/cate_a946*********************_10045991";
SignatureRequest signatureRequest = new SignatureRequest(method, host, version, canonicalUri);*/
// Construct the value of the Authorization header.
generateSignature(signatureRequest);
// Use HTTPClient to send the request.
callApi(signatureRequest);
}
private static void generateSignature(SignatureRequest signatureRequest) {
try {
// Step 1: Construct a canonicalized header
String canonicalHeaders = buildCanonicalHeaders(signatureRequest);
// Step 2: Construct a canonicalized resource
String canonicalQueryString = buildQueryString(signatureRequest);
// Step 3: Construct a string-to-sign
String stringToSign = buildStringToSign(signatureRequest, canonicalQueryString, canonicalHeaders);
// Step 4: Calculate the signature string
String signature = signString(stringToSign);
// Step 5: Specify the Authorization header.
String authorization = "acs " + ACCESS_KEY_ID + ":" + signature;
signatureRequest.headers.put("Authorization", authorization);
} catch (Exception ex) {
throw new IllegalArgumentException(ex.toString());
}
}
private static void callApi(SignatureRequest signatureRequest) {
try {
// Send the request by using HttpClient.
String url = "https://" + signatureRequest.host + signatureRequest.canonicalUri;
URIBuilder uriBuilder = new URIBuilder(url);
// Specify request parameters.
signatureRequest.queryParams.forEach((key, value) -> uriBuilder.addParameter(key, String.valueOf(value)));
HttpUriRequest httpRequest;
switch (signatureRequest.httpMethod) {
case "GET":
httpRequest = new HttpGet(uriBuilder.build());
break;
case "POST":
HttpPost httpPost = new HttpPost(uriBuilder.build());
if (signatureRequest.bodyByteArray != null) {
httpPost.setEntity(new ByteArrayEntity(signatureRequest.bodyByteArray, ContentType.create(signatureRequest.headers.get("Content-Type"))));
}
httpRequest = httpPost;
break;
case "PUT":
HttpPut httpPut = new HttpPut(uriBuilder.build());
if (signatureRequest.bodyByteArray != null) {
httpPut.setEntity(new ByteArrayEntity(signatureRequest.bodyByteArray, ContentType.create(signatureRequest.headers.get("Content-Type"))));
}
httpRequest = httpPut;
break;
case "DELETE":
httpRequest = new HttpDelete(uriBuilder.build());
break;
default:
System.out.println("Unsupported HTTP method: " + signatureRequest.httpMethod);
throw new IllegalArgumentException("Unsupported HTTP method");
}
// Specify HTTP request headers.
signatureRequest.headers.forEach(httpRequest::addHeader);
// Send the request.
try (CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = httpClient.execute(httpRequest)) {
String result = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println(result);
} catch (IOException e) {
// Handle errors.
System.out.println("Failed to send request");
throw new IllegalArgumentException(e.toString());
}
} catch (URISyntaxException e) {
// Handle errors.
System.out.println("Invalid URI syntax");
throw new IllegalArgumentException(e.toString());
}
}
private static String buildCanonicalHeaders(SignatureRequest signatureRequest) {
StringBuilder canonicalHeaders = new StringBuilder();
signatureRequest.headers.entrySet().stream()
.filter(entry -> entry.getKey().startsWith("x-acs-"))
.forEach(entry -> canonicalHeaders.append(entry.getKey().toLowerCase().trim()).append(":").append(entry.getValue().trim()).append("\n"));
return canonicalHeaders.toString();
}
private static String buildQueryString(SignatureRequest signatureRequest) {
StringBuilder queryBuilder = new StringBuilder(signatureRequest.canonicalUri);
if (!signatureRequest.queryParams.isEmpty()) {
queryBuilder.append("?");
}
for (Map.Entry<String, Object> entry : signatureRequest.queryParams.entrySet()) {
queryBuilder.append(entry.getKey());
String value = (String) entry.getValue();
if (value != null && !value.isEmpty()) {
queryBuilder.append("=").append(value).append("&");
} else {
queryBuilder.append("&");
}
}
String queryString = queryBuilder.toString();
if (queryString.endsWith("&")) {
queryString = queryString.substring(0, queryString.length() - 1);
}
return queryString;
}
private static String buildStringToSign(SignatureRequest signatureRequest, String canonicalQueryString, String canonicalHeaders) {
StringBuilder sb = new StringBuilder();
sb.append(signatureRequest.httpMethod).append("\n");
appendIfPresent(sb, signatureRequest.headers.get("Accept"));
appendIfPresent(sb, signatureRequest.headers.get("Content-MD5"));
appendIfPresent(sb, signatureRequest.headers.get("Content-Type"));
appendIfPresent(sb, signatureRequest.headers.get("Date"));
sb.append(canonicalHeaders);
sb.append(canonicalQueryString);
return sb.toString();
}
private static void appendIfPresent(StringBuilder sb, String value) {
if (value != null) {
sb.append(value).append("\n");
} else {
sb.append("\n");
}
}
private static String signString(String stringToSign) {
try {
Mac mac = Mac.getInstance(ALGORITHM_NAME);
mac.init(new SecretKeySpec(ACCESS_KEY_SECRET.getBytes(StandardCharsets.UTF_8), ALGORITHM_NAME));
byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
return DatatypeConverter.printBase64Binary(signData);
} catch (NoSuchAlgorithmException | InvalidKeyException ex) {
throw new IllegalArgumentException(ex.toString());
}
}
public static String md5Sum(byte[] buff) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] md5Bytes = md.digest(buff);
return DatatypeConverter.printBase64Binary(md5Bytes);
} catch (NoSuchAlgorithmException ex) {
throw new IllegalArgumentException(ex.toString());
}
}
}
References
For more information about the difference between RPC-style APIs and ROA-style APIs, see API styles.