2016-12-29 64 views
0

我讀過很多類似的問題,但沒有找到可以接受的答案。Drive REST API返回400 for files> 1mb

我正在寫簡單的驅動器上傳Gradle的任務,以便在成功構建之後上傳android.apk文件。我不使用Drive Java API,只使用REST請求。

這個任務檢索令牌:

task getToken << { 
    def keyStoreFile = file("SomeProject-PrivateKey.p12") 
    def keyStorePass = "notasecret" 
    def serviceAccountEmail = "[email protected]" 

    def keyStore = java.security.KeyStore.getInstance("PKCS12") 
    keyStore.load(keyStoreFile.newInputStream(), keyStorePass.toCharArray()) 
    def privateKey = keyStore.getKey(keyStore.aliases().nextElement(), keyStorePass.toCharArray()) 

    def JWTHeader = '{"alg":"RS256","typ":"JWT"}' 
    def JWTClaimSet = '{\n' + 
     ' "iss":' + serviceAccountEmail + ',\n' + 
     ' "scope":"https://www.googleapis.com/auth/drive",\n' + 
     ' "aud":"https://www.googleapis.com/oauth2/v4/token",\n' + 
     ' "exp":' + (System.currentTimeSeconds() + 5 * 60) + ',\n' + // + 5 minutes 
     ' "iat":' + System.currentTimeSeconds() + '\n' + 
     '}' 
    def JWT = new String(Base64.urlEncoder.encode(JWTHeader.bytes)) + 
     '.' + new String(Base64.urlEncoder.encode(JWTClaimSet.bytes)) 

    def signature = java.security.Signature.getInstance("SHA256withRSA") 
    signature.initSign(privateKey) 
    signature.update(JWT.bytes) 
    JWT += '.' + new String(Base64.urlEncoder.encode(signature.sign())) 

    System.out.print "assertion: " + JWT + "\n" 

    def authUrl = new URL("https://www.googleapis.com/oauth2/v4/token") 
    HttpURLConnection auth = authUrl.openConnection() 
    auth.setRequestMethod("POST") 
    auth.setRequestProperty("Host", "www.googleapis.com") 
    auth.setRequestProperty("Content-Type", "application/x-www-form-urlencoded") 
    auth.setDoOutput(true) 
    def body = 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer' + 
     '&assertion=' + JWT 
    auth.outputStream.write(body.bytes) 
    def reader = new BufferedReader(new InputStreamReader(auth.inputStream)) 

    StringBuilder sb = new StringBuilder() 
    for (int c; (c = reader.read()) >= 0;) 
    sb.append((char) c) 
    System.out.println(sb.toString()) 
} 

而這一次上傳文件到一些公共文件夾或文件夾[email protected]共享:

task uploadToDrive << { 
    File apk = file("test1.txt") 
    // File apk = file("test2.apk") 
    def url = new URL("https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart"); 

    HttpURLConnection drive = url.openConnection(); 
    drive.setRequestMethod("POST") 
    drive.setRequestProperty("Host", "www.googleapis.com") 
    drive.setRequestProperty("Authorization", "Bearer " + "ya29.ElnDA_idxn6dL4cji6Oh3dQbdCaMGtGfmIMwIDa4yrEgiL9G8I6qHeSoCNUwcfYESZiLBBaymYLWJQBuTgypqyOy_YVUNpwyd2Gf8rYLgAsSksNnruygoFBS9g") 
    drive.setRequestProperty("Content-Type", "multipart/related; boundary=foo_bar_baz") 

    String body = '\n' + 
     '--foo_bar_baz\n' + 
     'Content-Type: application/json; charset=UTF-8\n\n' + 
     '{\n' + 
     ' "name": "TEST",\n' + 
     ' "parents": [ "0BzkpQECQo2d2SEo5OTd4RHpnOFE" ]\n' + 
     '}\n\n' + 
     '--foo_bar_baz\n' + 
     'Content-Type: application/octet-stream\n\n' 
    String end = '--foo_bar_baz--' 

    drive.setFixedLengthStreamingMode(body.bytes.length + apk.length() + end.bytes.length)  // Content Length 

    drive.setDoOutput(true) 
    drive.setDoInput(true) 
    drive.outputStream.write(body.bytes) 
    apk.withInputStream { is -> 
    def buffer = new byte[1024]; 
    int len; 
    while ((len = is.read(buffer)) != -1) { 
     drive.outputStream.write(buffer, 0, len); 
    } 
    } 
    drive.outputStream.write(end.bytes) 

    def reader = new BufferedReader(new InputStreamReader(drive.inputStream)) 
    StringBuilder sb = new StringBuilder() 
    for (int c; (c = reader.read()) >= 0;) 
    sb.append((char) c); 
    System.out.println(sb.toString()) 
} 

對於小文件它的工作原理是!但是,當我嘗試上傳真正的.apk文件或甚至〜1Mb圖像gradle失敗時:

任務':uploadToDrive'的執行失敗。 服務器返回的HTTP響應碼:400爲URL:https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart

任何想法?

+0

官方的建議是不要使用多部分上傳大文件。移動設備尤其如此。你應該使用可恢復的上傳。我不知道這是否解釋了400,但是無論如何你應該做的事情。 – pinoyyid

+0

您可能希望檢查在處理錯誤響應時描述解決方案的[處理API錯誤](https://developers.google.com/drive/v3/web/handle-errors)。還可以嘗試使用[可恢復上載](https://developers.google.com/drive/v3/web/manage-uploads#resumable)來檢查是否仍然會遇到同樣的錯誤。最後,您可能想檢查相關的[SO帖子](http://stackoverflow.com/a/24459799/5995040),使用特定於Android的API可能會幫助您解決所有這些問題。 –

+0

以下是Google的GitHub - [Google Drive Android API演示](https://github.com/googledrive/android-demos)和教程 - [在Android中集成Google Drive](https://www.numetriclabz。 com/integrate-google-drive-in-android-tutorial /)這將幫助你理解Android中Google Drive的代碼實現。希望這些信息有幫助。 –

回答

0

不是一個真正的答案(爲什麼是400?),但它解決了這個問題。 感謝Mr.Rebot & pinoyyid

可恢復上傳的例子,作品大文件:

task uploadResumable << { 
    File apk = file("dog.jpg") 
    def url = new URL("https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable"); 

    HttpURLConnection drive = url.openConnection(); 
    drive.setRequestMethod("POST") 
    drive.setRequestProperty("Host", "www.googleapis.com") 
    drive.setRequestProperty("Authorization", "Bearer " + "ya29.ElnDA_idxn6dL4cji6Oh3dQbdCaMGtGfmIMwIDa4yrEgiL9G8I6qHeSoCNUwcfYESZiLBBaymYLWJQBuTgypqyOy_YVUNpwyd2Gf8rYLgAsSksNnruygoFBS9g") 
    drive.setRequestProperty("Content-Type", "application/json; charset=UTF-8") 
    drive.setRequestProperty("X-Upload-Content-Type", "image/jpeg") 

    String body = '\n' + 
     '{\n' + 
     ' "name": "DOGresum",\n' + 
     ' "parents": [ "0BzkpQECQo2d2SEo5OTd4RHpnOFE" ]\n' + 
     '}\n\n'; 

    drive.setFixedLengthStreamingMode(body.bytes.length)  // Content Length 
    drive.setDoOutput(true) 
    drive.setDoInput(true) 
    drive.outputStream.write(body.bytes) 

    // response header example: 
    //  -> Location: [https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable&upload_id=AEnB...] 
    // get "Location" header 
    String loc = drive.getHeaderFields().get("Location") 

    // trim '[' and ']' brackets and get URL query 
    def query = new URL(loc[1..-2]).query 

    // find upload_id value 
    String uploadId; 
    query.split('&').each { 
    if (it.split('=')[0] == 'upload_id') 
     uploadId = it.split('=')[1] 
    } 

    // start new upload 
    def url2 = new URL("https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable&upload_id=" + uploadId); 
    HttpURLConnection drive2 = url2.openConnection() 
    drive2.setRequestMethod('POST') 
    drive2.setRequestProperty("Content-Type", "image/jpeg") 
    drive2.setFixedLengthStreamingMode(apk.bytes.length)  // Content Length 
    drive2.setDoOutput true 
    drive2.setDoInput true 
    drive2.outputStream.write apk.bytes 
}