當我使用HttpClient工具請求CloudStack API時,總是返回401錯誤信息,搗騰了一天,最後還是耐心的解決了這個問題,解決辦法如下:
問題分析:根據提示信息要麼是Api Key寫錯,要麼是生成signature錯誤。
1) Api key問題:
在UI界面生成的Api Key 和 Secret Key 會在mysql數據庫中保存,表名爲user,字段名爲api_key和secret_key,我建議複製數據庫裏面的這兩個密鑰值,因爲在頁面複製的api key或者secret key首尾可能會帶有縮進字符,從而在請求的路徑中匹配數據庫裏的密鑰不正確。筆者經歷過。
2) Signature問題:
後加入的參數未加入到計算signature的過程中:如下代碼
以上兩個是筆者遇到的問題。
最後經過調整完整版如下:
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
import yourpackage.utils.HttpClientUtil;//自定義的工具
@Test
public void testHttpClientUitl() throws Exception{
String baseUrl = "http://localhost:8080/client/api?";
String security = "H65hqe7U-T59TwpD2-0dNYbfcDYKaAnrQQoTFghyiMhMCrGm-pLJV5hGPc8fTHqn6XYxUowJNxjMXxilp4VY2Q";
String apikey = "2n9_BGYlgUjLZMiHZi5U58_88QCcWLYHwm80WYoc8rd91XMsnlZ4kD9xvg3AMBKpuxz3P8OwOwJhtX-HpelrFg";
TreeMap treeMap = new TreeMap((v1,v2)->{
if(v1 == null || v2 == null){
return 0;
}
return String.valueOf(v1).compareTo(String.valueOf(v2));
});
treeMap.put("command", "listUsers");
treeMap.put("apiKey", apikey);
treeMap.put("response", "json");
StringBuilder str = new StringBuilder();
treeMap.forEach((k,v)->{
try {
String encoded_v = URLEncoder.encode(String.valueOf(v), "UTF-8").replaceAll("\\+", "%20");
str.append(k).append("=").append(encoded_v).append("&");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
});
str.replace(str.lastIndexOf("&"), str.length(), "");
System.out.println(str.toString());
Mac mac = Mac.getInstance("HmacSHA1");
SecretKeySpec keySpec =new SecretKeySpec(security.getBytes(),"HmacSHA1");
mac.init(keySpec);
mac.update(str.toString().toLowerCase().getBytes());
byte[] encryptedBytes = mac.doFinal();
String encodeBase64String = URLEncoder.encode(Base64.encodeBase64String(encryptedBytes), "UTF-8").replaceAll("\\+", "%20");
System.out.println(encodeBase64String);
str.append("&signature=").append(encodeBase64String);
System.out.println(str);
String httpUrl = baseUrl+str.toString();
System.out.println(httpUrl);
HttpClientUtil httpClient = HttpClientUtil.getInstance();
String reponseContent = httpClient.sendHttpGet(httpUrl);
System.out.println(reponseContent);
}
最後,需要注意的是URLEncoder.encode(str)編碼時會將空格轉化爲+號,需要將+號替換爲%20,如下代碼:URLEncoder.encode(str).replaceAll("\\+","%20");
爲什麼轉化爲%20,看以下鏈接查看URL編碼部分知識。
https://www.w3school.com.cn/html/html_urlencode.asp
https://www.w3school.com.cn/tags/html_ref_urlencode.html
以上是筆者在剛開始使用cloudstack調用API的過程中遇到的問題,總結下問題。希望對你有所幫助。