2013-04-09 461 views
0

好吧,這真令人沮喪。我使用我的API密鑰非常好。身份驗證沒有問題,令牌生成良好,會話密鑰也可以。發送HTTP POST請求時無效的方法簽名

但是,當我運行playlist.create,播放列表不會創建。

我今天幾乎從零開始,重新編寫了大部分代碼。我成功創建了16個播放列表,沒有錯誤。但今天,相同的代碼無法正常工作。我根本沒有碰它,但錯誤。

private static void buildPlaylist() { 

    String mood = "Happy"; 
    System.out.println("\nMood is " + mood + "\n\n"); 

    String title = URLEncoder.encode(mood + " " + new Date().getTime(), "UTF-8"); 
    String description = URLEncoder.encode("For when you are " + mood + ". Created by MoodicPlayer.", "UTF-8"); 

    MessageDigest md = MessageDigest.getInstance("MD5"); 

    String apiSig = "api_key" + key + "description" + description + "methodplaylist.createsk" + sessionKey + "title" + title + secret; 
    md.update(apiSig.getBytes()); 
    byte byteData[] = md.digest(); 
    //convert the byte to hex format 
    StringBuffer sb = new StringBuffer(); 
    for (int i = 0; i < byteData.length; i++) { 
     sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1)); 
    } 
    String hashedSig = sb.toString(); 

    // FOR DEBUGGING 
    System.out.println("api_key = " + key); 
    System.out.println("api_sig = " + hashedSig); 
    System.out.println("session key = " + sessionKey); 
    // FOR DEBUGGING 

    String urlParameters = "method=playlist.create&api_key="+ key + "&api_sig=" + hashedSig + "&description=" + description + "&sk=" + sessionKey + "&title=" + title; 
    String request = "http://ws.audioscrobbler.com/2.0/"; 

    URL url = new URL(request); 
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();  
    connection.setDoOutput(true); 
    connection.setDoInput(true); 
    connection.setInstanceFollowRedirects(false); 
    connection.setRequestMethod("POST"); 
    connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); 
    connection.setRequestProperty("charset", "utf-8"); 
    connection.setRequestProperty("Content-Length", "" + Integer.toString(urlParameters.getBytes().length)); 
    connection.setUseCaches(false); 

    DataOutputStream wr = new DataOutputStream(connection.getOutputStream()); 
    wr.writeBytes(urlParameters); 
    wr.flush(); 
    wr.close(); 

    InputStream is = null; 
    Scanner s = null; 
    try { 
     if (connection.getResponseCode() != 200) { 
      s = new Scanner(connection.getErrorStream()); 
     } else { 
      is = connection.getInputStream(); 
      s = new Scanner(is); 
     } 
     s.useDelimiter("\\Z"); 
     String response = s.next(); 
     System.out.println("\nResponse: " + response + "\n\n"); 
     BufferedWriter out = new BufferedWriter(new FileWriter("requestCreate.xml")); 
     out.write(response); 
     out.close(); 
    } catch (IOException e2) { 
     e2.printStackTrace(); 
    } 

    // FOR DEBUGGING 
    try { 
     System.out.println("Response Code: " + connection.getResponseCode()); 
     System.out.println("Response Message: " + connection.getResponseMessage()); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    // FOR DEBUGGING 
    connection.disconnect(); 
} 

和輸出:

Starting test for creating playlist... 

Mood is Happy 
api_key = xxxxx 
api_sig = xxxxxx 
session key = xxxxx 

Response: <?xml version="1.0" encoding="utf-8"?> 
<lfm status="failed"> 
<error code="13"> 
    Invalid method signature supplied 
</error> 
</lfm> 


Response Code: 403 
Response Message: Forbidden 

我檢查了代碼,但找不到任何錯誤。我的意思是16小時前的代碼很好,突然不工作了!


出於安全考慮,我無法向您顯示我的安全密鑰。但是,我確實編寫了一個快速程序來查找last.fm會話密鑰:http://github.com/thekarangoel/LastFMSessionKeyFinder只需在last.fm/api註冊,在程序中輸入您的API密鑰和密鑰,即可獲得測試API調用所需的所有內容。

+0

它看起來像你寫你的URL參數代入實體主體。他們不應該成爲網址的一部分嗎? – Pace 2013-04-09 18:34:41

+0

我不這麼認爲,因爲這是一個POST請求。 – 2013-04-09 19:42:41

回答

2

生成MD5散列時,使用的是URL編碼版本titledescription值。 The documentation不會這麼說。嘗試使用非URL編碼值(但它們確實需要使用UTF-8編碼)。網址編碼只能在實際的網址數據中使用(與其名稱不同)。

試試這個:

private static void buildPlaylist() { 

    String mood = "Happy"; 
    System.out.println("\nMood is " + mood + "\n\n"); 

    String title = mood + " " + new Date().getTime(); 
    String description = "For when you are " + mood + ". Created by MoodicPlayer."; 

    MessageDigest md = MessageDigest.getInstance("MD5"); 

    String apiSig = "api_key" + key + "description" + description + "methodplaylist.createsk" + sessionKey + "title" + title + secret; 
    md.update(apiSig.getBytes("UTF-8")); 
    byte byteData[] = md.digest(); 
    //convert the byte to hex format 
    StringBuffer sb = new StringBuffer(byteData.length*2); 
    for (int i = 0; i < byteData.length; i++) { 
     sb.append(String.format("%02X", byteData[i]));  
    } 
    String hashedSig = sb.toString(); 

    // FOR DEBUGGING 
    System.out.println("api_key = " + key); 
    System.out.println("api_sig = " + hashedSig); 
    System.out.println("session key = " + sessionKey); 
    // FOR DEBUGGING 

    String urlParameters = "method=playlist.create&api_key="+ key + "&api_sig=" + hashedSig + "&description=" + URLEncoder.encode(description, "UTF-8") + "&sk=" + sessionKey + "&title=" + URLEncoder.encode(title, "UTF-8"); 
    String request = "http://ws.audioscrobbler.com/2.0/"; 

    URL url = new URL(request); 
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();  
    connection.setDoOutput(true); 
    connection.setDoInput(true); 
    connection.setInstanceFollowRedirects(false); 
    connection.setRequestMethod("POST"); 
    connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); 
    connection.setRequestProperty("charset", "utf-8"); 
    connection.setRequestProperty("Content-Length", "" + Integer.toString(urlParameters.getBytes().length)); 
    connection.setUseCaches(false); 

    DataOutputStream wr = new DataOutputStream(connection.getOutputStream()); 
    wr.writeBytes(urlParameters); 
    wr.flush(); 
    wr.close(); 

    ... 
} 
+0

我試過這個,也不管用。實際上API說在生成簽名時對參數進行編碼:'確保你的參數是utf8編碼的.' – 2013-04-09 19:46:03

+0

@ user2059238 utf-8編碼不等於URL編碼。這個答案是正確的,適用於我(除了在代碼中缺少的括號) – jkovacs 2013-04-09 20:34:05

+0

我複製你的答案,但仍然得到一個403禁止錯誤。不知道爲什麼/如何爲你工作。 – 2013-04-09 22:39:19