Topik ini menjelaskan cara mengirim permintaan HTTP untuk memanggil operasi API Alibaba Cloud dalam arsitektur berorientasi sumber daya (ROA).
Sintaks permintaan dan metode tanda tangan V2 sudah tidak digunakan lagi. Gunakan sintaks permintaan dan metode tanda tangan V3.
Sintaks Permintaan HTTP
Tabel berikut menjelaskan parameter yang termasuk dalam permintaan API Alibaba Cloud yang lengkap.
Komponen | Diperlukan | Deskripsi | Contoh |
Protokol | Ya | Protokol permintaan. Anda dapat melihat protokol yang didukung oleh API di Metadata API. Jika API mendukung baik | https:// |
Titik akhir | Ya | Titik akhir API layanan Alibaba Cloud. Topik yang mencantumkan titik akhir setiap layanan Alibaba Cloud tersedia. Anda dapat melihat titik akhir suatu layanan di berbagai wilayah dalam topik-topik tersebut. | bailian.cn-beijing.aliyuncs.com |
parameter_URI_sumberdaya | Ya | URL dari operasi. URL berisi jalur API dan parameter permintaan di komponen jalur dan kueri. | /{WorkspaceId}/datacenter/category |
RequestHeader | Ya | Header permintaan. Dalam banyak kasus, informasi seperti nomor versi API, titik akhir, dan informasi autentikasi disertakan. Untuk informasi lebih lanjut, lihat bagian Parameter untuk RequestHeader dari topik ini. | Accept:application/json Authorization:acs YourAccessKeyId:s8ZMF/eAIvvPJwehLLha0bVNFJ0= Content-MD5:LP54yxk8n7KqF1PPgbJizw== Content-Type:application/json Date:Rab, 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 | Ya | Parameter spesifik operasi dalam badan permintaan. Untuk informasi lebih lanjut, kunjungi OpenAPI Explorer. | {"CategoryName":"test","CategoryType":"UNSTRUCTURED"} |
HTTPMethod | Ya | Metode permintaan API ROA. Nilai valid: PUT, POST, GET, dan DELETE. Anda dapat melihat metode permintaan yang didukung oleh API di Referensi API. | POST |
Parameter untuk RequestHeader
Tabel berikut menjelaskan parameter yang termasuk dalam permintaan API Alibaba Cloud yang lengkap.
Parameter | Tipe | Diperlukan | Deskripsi | Contoh |
Accept | String | Tidak | Format respons. Jika Anda tidak menentukan parameter ini, respons akan dalam format XML. Untuk memanggil operasi API bergaya ROA, atur nilainya menjadi | application/json |
Content-MD5 | String | Tidak | Nilai hash MD5 128-bit yang dikodekan Base64 dari badan permintaan. | LP54yxk8n7KqF1PPgbJizw== |
Date | String | Ya | Timestamp permintaan. Timestamp berlaku selama 15 menit. Anda harus menginisiasi permintaan dalam waktu 15 menit setelah timestamp dibuat. Tentukan waktu dalam GMT sesuai dengan HTTP 1.1. Contoh: Sel 9 Apr 2019 07:35:29 GMT. | Rab, 16 Apr 2025 03:44:46 GMT |
Host | String | Ya | Titik akhir API layanan Alibaba Cloud. Untuk informasi lebih lanjut, lihat bagian Struktur permintaan HTTP dari topik ini. | bailian.cn-beijing.aliyuncs.com |
x-acs-signature-method | String | Ya jika permintaan tidak anonim | Metode enkripsi string tanda tangan. Atur nilainya menjadi | HMAC-SHA1 |
x-acs-signature-nonce | String | Ya | Nomor unik dan acak yang digunakan untuk mencegah serangan pemutaran jaringan. Untuk mencegah serangan pemutaran, kami sarankan Anda menggunakan angka yang berbeda untuk setiap permintaan. | ef34aae7-7bd2-413d-a541-680cd2c48538 |
x-acs-signature-version | String | Tidak | Versi tanda tangan. Atur nilainya menjadi | 1.0 |
x-acs-version | String | Ya | Versi API. Anda dapat memperoleh versi API di OpenAPI Explorer atau di Metadata API. | 2023-12-29 |
Authorization | String | Ya jika permintaan tidak anonim | Informasi autentikasi yang digunakan untuk memverifikasi validitas permintaan. Tentukan nilai dalam format Parameter Signature menentukan string tanda tangan dari permintaan. Untuk informasi lebih lanjut, lihat bagian Metode tanda tangan dari topik ini. | acs YourAccessKeyId:D9uFJAJgLL+dryjBfQK+YeqGtoY= |
Metode tanda tangan
Anda harus menandatangani semua permintaan API HTTP dan HTTPS untuk memastikan keamanan. Saat permintaan mencapai gateway API Alibaba Cloud, gateway akan menghitung ulang tanda tangan berdasarkan parameter permintaan dan header permintaan, lalu membandingkan tanda tangan yang dihitung dengan tanda tangan dalam permintaan untuk memverifikasi identitas pemanggil API. Mekanisme ini memastikan integritas dan keamanan data. Bagian ini menjelaskan cara menghitung tanda tangan.
Semua permintaan dan respons dikodekan dalam UTF-8.
Langkah 1: Buat header kanonisasi
Header kanonisasi adalah header HTTP non-standar. Header non-standar adalah header yang namanya diawali dengan x-acs- dalam permintaan. Untuk membuat header kanonisasi, ikuti langkah-langkah berikut:
Konversikan nama header permintaan yang diawali dengan
x-acs-dalam header permintaan menjadi huruf kecil dan urutkan secara leksikografis naik.Hapus spasi awal dan akhir dari nama dan nilai header permintaan.
Tambahkan pembatas
\nke akhir setiap header, termasuk header terakhir, dan gabungkan semua header.
Contoh:
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
Langkah 2: Buat sumber daya kanonisasi
Sumber daya kanonisasi adalah deskripsi kanonisasi dari sumber daya yang ingin Anda akses. Ikuti langkah-langkah berikut untuk membuat sumber daya kanonisasi:
Urutkan parameter dalam string kueri permintaan berdasarkan nama dalam urutan abjad dan gabungkan parameter menggunakan ampersand (
&) untuk menghasilkan string kueri yang diurutkan.Gabungkan jalur sumber daya yang diminta dengan string kueri yang diurutkan menggunakan tanda tanya (
?) untuk mendapatkan sumber daya kanonisasi. Jalur sumber daya adalah bagian antara titik akhir dan string kueri. Jalur tersebut mencakup garis miring maju (/) setelah titik akhir tetapi tidak termasuk tanda tanya (?) sebelum string kueri. Jika permintaan tidak berisi string kueri, gunakan jalur sumber daya sebagai sumber daya kanonisasi.
Contoh:
/llm-p2e4XXXXXXXXsvtn/datacenter/categoryLangkah 3: Buat string-to-sign
Buat string-to-sign berdasarkan pseudocode berikut:
String stringToSign =
HTTPMethod + "\n" +
Accept + "\n" +
ContentMD5 + "\n" +
ContentType + "\n" +
Date + "\n" +
CanonicalizedHeaders +
CanonicalizedResourceParameter | Deskripsi |
HTTPMethod | Metode HTTP dalam huruf besar, seperti POST atau GET. |
Accept | Nilai header Accept. Atur nilainya menjadi string kosong jika header ini tidak ada. |
ContentMD5 | Nilai header Content-MD5. Atur nilainya menjadi string kosong jika header ini tidak ada. |
ContentType | Nilai header Content-Type. Atur nilainya menjadi string kosong jika header ini tidak ada. Catatan Tipe Multipurpose Internet Mail Extensions (MIME) dari badan permintaan. |
Date | Nilai header Date. |
CanonicalizedHeaders | Header kanonisasi yang diperoleh dari Langkah 1: Buat header kanonisasi dari topik ini. |
CanonicalizedResource | Sumber daya kanonisasi yang diperoleh dari Langkah 2: Buat sumber daya kanonisasi dari topik ini. |
Contoh:
POST
application/json
LP54yxk8n7KqF1PPgbJizw==
application/json
Rab, 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/categoryLangkah 4: Hitung string tanda tangan
Hitung nilai kode otentikasi pesan berbasis hash (HMAC) dari string-to-sign menggunakan algoritma HMAC-SHA1 dan kodekan nilai HMAC menjadi string tanda tangan berdasarkan aturan pengkodean Base64. Untuk informasi lebih lanjut tentang HMAC, lihat RFC 2104.
String signature = Base64(HMAC_SHA1(SigningKey, stringToSign))Atur parameter SigningKey ke rahasia AccessKey Anda. Untuk informasi lebih lanjut, lihat Buat Pasangan AccessKey.
Contoh:
s8ZMF/eAIvvPJwehLLha0bVNFJ0=Langkah 5: Tentukan header Authorization.
Setelah Anda memperoleh string tanda tangan, buat nilai header Authorization berdasarkan kode berikut:
String Authorization = "acs " + AccessKeyId + ":" + signatureContoh:
acs YourAccessKeyId:s8ZMF/eAIvvPJwehLLha0bVNFJ0=Langkah 6: Tambahkan tanda tangan ke permintaan dankirim permintaan.
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:Rab, 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"}Contoh tanda tangan
Java
Dalam contoh ini, lingkungan runtime JDK 1.8 digunakan. Sesuaikan parameter berdasarkan kebutuhan bisnis Anda.
Untuk menggunakan metode tanda tangan di Java, tambahkan dependensi Maven berikut ke file pom.xml:
<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) {
// Contoh 1: Kirim permintaan POST.
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);
/*// Contoh 2: Kirim permintaan GET.
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");*/
/*// Contoh 3: Kirim permintaan DELETE.
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);*/
// Buat nilai header Authorization.
generateSignature(signatureRequest);
// Gunakan HTTPClient untuk mengirim permintaan.
callApi(signatureRequest);
}
private static void generateSignature(SignatureRequest signatureRequest) {
try {
// Langkah 1: Buat header kanonisasi
String canonicalHeaders = buildCanonicalHeaders(signatureRequest);
// Langkah 2: Buat sumber daya kanonisasi
String canonicalQueryString = buildQueryString(signatureRequest);
// Langkah 3: Buat string-to-sign
String stringToSign = buildStringToSign(signatureRequest, canonicalQueryString, canonicalHeaders);
// Langkah 4: Hitung string tanda tangan
String signature = signString(stringToSign);
// Langkah 5: Tentukan header Authorization.
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 {
// Kirim permintaan menggunakan HttpClient.
String url = "https://" + signatureRequest.host + signatureRequest.canonicalUri;
URIBuilder uriBuilder = new URIBuilder(url);
// Tentukan parameter permintaan.
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("Metode HTTP tidak didukung: " + signatureRequest.httpMethod);
throw new IllegalArgumentException("Metode HTTP tidak didukung");
}
// Tentukan header permintaan HTTP.
signatureRequest.headers.forEach(httpRequest::addHeader);
// Kirim permintaan.
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) {
// Tangani kesalahan.
System.out.println("Gagal mengirim permintaan");
throw new IllegalArgumentException(e.toString());
}
} catch (URISyntaxException e) {
// Tangani kesalahan.
System.out.println("Sintaks URI tidak valid");
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());
}
}
}
Referensi
Untuk informasi lebih lanjut tentang perbedaan antara API bergaya RPC dan API bergaya ROA, lihat Gaya API.