简体   繁体   English

使用REST API将图片文件上传到Google云端硬盘时出错

[英]Error uploading image file to Google Drive using REST API

I am working with the Google Drive for the first time. 我是第一次使用Google云端硬盘。 I am trying to upload a jpg file to my Google Drive through my app. 我正在尝试通过我的应用将jpg文件上传到我的Google云端硬盘。 I have completed the OAuth 2.0 authorization for account login and drive permission. 我已经完成了针对帐户登录和驱动器权限的OAuth 2.0授权。 I have successfully uploaded the file to Google Drive also following the instructions given here https://developers.google.com/drive/api/v3/manage-uploads?refresh=1 我也按照此处给出的说明将文件成功上传到Google云端硬盘https://developers.google.com/drive/api/v3/manage-uploads?refresh=1

The issue is with the uploaded file. 问题出在上传的文件上。 The image is not saved there as an image. 该图像未保存为图像。 What should be the form of the request body here? 请求主体的形式应该是什么?

Here is the code snippet I have used to upload the image file using Google REST API. 这是我使用Google REST API上传图像文件的代码片段。

OkHttpClient client = new OkHttpClient();
            RequestBody body = RequestBody.create(MediaType.parse("application/json"), file);
            Request request = new Request.Builder()
                    .url("https://www.googleapis.com/upload/drive/v3/files?uploadType=media")
                    .addHeader("Content-Type", "image/jpeg")
                    .addHeader("Content-Length", "36966.4")
                    .addHeader("Authorization", String.format("Bearer %s", accessToken))
                    .post(body)
                    .build();
            Response response = null;
            try {
                response = client.newCall(request).execute();
                successCode = String.valueOf(response.code());
            }catch (IOException e){
                e.printStackTrace();
            }

Here "file" is the Base64 encoded string of the image. 这里的“文件”是图像的Base64编码的字符串。

Its just giving the expected http ok 200 code. 它只是给出了预期的http ok 200代码。 Also need to know how to set the title for the file while uploading on Google Drive. 还需要知道在Google云端硬盘上上传时如何设置文件标题。

You have mentioned wrong content type in the request. 您在请求中提到了错误的内容类型。 It should be 它应该是

RequestBody body = RequestBody.create(MediaType.parse("image/jpeg"), file);

(Posted on behalf of the question author) . (代表问题作者发布)

Here is the answer to all my questions. 这是我所有问题的答案。 The questions were 问题是

  1. Create a folder on the Google drive with a desired name. 在Google驱动器上创建一个具有所需名称的文件夹。
  2. Upload a file (image/audio/video) to that particular folder. 将文件(图像/音频/视频)上传到该特定文件夹。

Let's start with the point #1. 让我们从第一点开始。 Here is the working code to create a folder on the Google drive with a desired name. 这是在Google驱动器上使用所需名称创建文件夹的工作代码。 I would like to mention one more thing that is related to OAuth 2.0 authorization. 我想提一提与OAuth 2.0授权有关的另一件事。 As per Google guidance I have used the code from Codelab. 根据Google的指导,我使用了Codelab的代码。 Here is the link to get the code https://codelabs.developers.google.com/codelabs/appauth-android-codelab/?refresh=1#0 The scope should be the API provided by the Google for that particular service. 这是获取代码的链接https://codelabs.developers.google.com/codelabs/appauth-android-codelab/?refresh=1#0范围应为Google为该特定服务提供的API。 For me it is " https://www.googleapis.com/auth/drive.file ". 对我而言,它是“ https://www.googleapis.com/auth/drive.file ”。

String metaDataFile = "{\"name\": \"folderName\","+ "\"mimeType\": \"application/vnd.google-apps.folder\"}";
            RequestBody requestBodyMetaData = RequestBody.create(MediaType.parse("application/json; charset=UTF-8"), metaDataFile);
            Request request = new Request.Builder()
                    .url("https://www.googleapis.com/drive/v3/files?")
                    .addHeader("Content-Type", "application/json")
                    .addHeader("Authorization", String.format("Bearer %s", accessToken))
                    .post(requestBodyMetaData)
                    .build();
            Response response = null;
            OkHttpClient client = new OkHttpClient();
            try {
                response = client.newCall(request).execute();
                successCode = String.valueOf(response.code());
            }catch (IOException e){
                e.printStackTrace();
            }

Now you have to get the folder id. 现在,您必须获取文件夹ID。 Here is the code to get the folder id. 这是获取文件夹ID的代码。

Request request = new Request.Builder()
                    .url("https://www.googleapis.com/drive/v3/files")
                    .addHeader("Authorization", String.format("Bearer %s", accessToken))
                    .addHeader("Accept", "application/json")
                    .build();
            Response response = null;
            OkHttpClient client = new OkHttpClient();
            try {
                response = client.newCall(request).execute();
                String jsonFile = response.body().string();
                JSONObject jsonObject = new JSONObject(jsonFile);
                JSONArray jsonArray = jsonObject.getJSONArray("files");
                for (int i=0; i<jsonArray.length(); i++){
                    JSONObject json = jsonArray.getJSONObject(i);
                    String fileName = json.getString("name");
                    if (fileName.equalsIgnoreCase("folderName")) {
                        folderId = json.getString("id");
                        if (!folderId.equalsIgnoreCase(""))
                            preferences.setFolderCreated(true, folderId);
                        break;
                    }
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
            catch (JSONException e){
                e.printStackTrace();
            }
            catch (NullPointerException e){
                e.printStackTrace();
            }

This folder id is needed to identify the folder where we are going to upload the file. 需要此文件夹ID来标识我们要将文件上传到的文件夹。 Select the file from your list and then pass that file in the byte[] format to this code. 从列表中选择文件,然后将该文件以byte []格式传递给此代码。 Here we have to use mediatype as multipart because if we use simple upload (media) we cannot set a desired name to the uploaded file. 在这里,我们必须将mediatype用作多部分,因为如果我们使用简单的上载(媒体),则无法为上载的文件设置所需的名称。

String metaDataFile = "{\"name\":\"uploadFileName\"," + "\"parents\" : [\""+ pref.getFolderId()+"\"]}"; // json type metadata

                //attaching metadata to our request object
                RequestBody requestBodyMetaData = RequestBody
                        .create(MediaType.parse("application/json; charset=UTF-8"), metaDataFile);
                RequestBody body = RequestBody.create(MediaType.parse("audio/mp4"), file);
                String size = String.valueOf(file.length);

                //passing both meta data and file content for uploading
                RequestBody requestBody = new MultipartBody.Builder()
                        .setType(MultipartBody.FORM)
                        .addFormDataPart("Metadata", null, requestBodyMetaData)
                        .addFormDataPart("Media", null, body)
                        .build();
                //Requesting the api
                Request request = new Request.Builder()
                        .url("https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart")
                        .addHeader("Authorization", String.format("Bearer %s", accessToken))
                        .addHeader("Content-Type", "multipart/related; boundary=100")
                        .addHeader("Content-Length", size)
                        .addHeader("Accept", "application/json")
                        .post(requestBody)
                        .build();
                Response response = null;
                OkHttpClient client = new OkHttpClient();
                try {
                    response = client.newCall(request).execute();
                    String json = response.body().string();
                    successCode = String.valueOf(response.code());
                } catch (IOException e) {
                    e.printStackTrace();
                }

This is the complete example using googleapiclient 这是使用googleapiclient的完整示例

//variables
private GoogleApiClient mGoogleApiClient;
private Bitmap mBitmapToSave;

now call this method on button click 现在单击按钮时调用此方法

//method to save file(Image type)
private void saveFileToDrive() {

    final Bitmap image = mBitmapToSave;
    Drive.DriveApi.newDriveContents(mGoogleApiClient)
            .setResultCallback(new ResultCallback<DriveContentsResult>() {

        @Override
        public void onResult(DriveContentsResult result) {

            if (!result.getStatus().isSuccess()) {
                Log.i("ERROR", "Failed to create new contents.");
                return;
            }


            OutputStream outputStream = result.getDriveContents().getOutputStream();
            // Write the bitmap data from it.
            ByteArrayOutputStream bitmapStream = new ByteArrayOutputStream();
            image.compress(Bitmap.CompressFormat.PNG, 100, bitmapStream);
            try {
                outputStream.write(bitmapStream.toByteArray());
            } catch (IOException e1) {
                Log.i("ERROR", "Unable to write file contents.");
            }
            // Create the initial metadata - MIME type and title.
            // Note that the user will be able to change the title later.
            MetadataChangeSet metadataChangeSet = new MetadataChangeSet.Builder()
                    .setMimeType("image/jpeg").setTitle("Android Photo.png").build();
            // Create an intent for the file chooser, and start it.
            IntentSender intentSender = Drive.DriveApi
                    .newCreateFileActivityBuilder()
                    .setInitialMetadata(metadataChangeSet)
                    .setInitialDriveContents(result.getDriveContents())
                    .build(mGoogleApiClient);
            try {
                startIntentSenderForResult(
                        intentSender, REQUEST_CODE_CREATOR, null, 0, 0, 0);
            } catch (SendIntentException e) {
                Log.i("ERROR", "Failed to launch file chooser.");
            }
        }
    });
}

@Override
protected void onResume() {
    super.onResume();
    if (mGoogleApiClient == null) {
        // Create the API client and bind it to an instance variable.
        // We use this instance as the callback for connection and connection
        // failures.
        // Since no account name is passed, the user is prompted to choose.
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addApi(Drive.API)
                .addScope(Drive.SCOPE_FILE)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();
    }
    // Connect the client. Once connected, the camera is launched.
    mGoogleApiClient.connect();
}

@Override
protected void onPause() {
    if (mGoogleApiClient != null) {
        mGoogleApiClient.disconnect();
    }
    super.onPause();
}

Ref Upload image to a google drive using google drive api programatically in android 在Android中以编程方式使用Google Drive API将图像上传到Google Drive

Thanks to all of you for your efforts specially Coder. 感谢大家的辛勤工作,特别是Coder。 I made it. 我做到了。 Here is the solution to the file data format issue. 这是文件数据格式问题的解决方案。 Its just a simple tweak in the header part in the request builder. 这只是对请求生成器中标头部分的简单调整。 We have to add the Content-Type with the value "application/json" in the request header and the request body with the "image/jpeg". 我们必须在请求标头中添加Content-Type,其值为“ application / json”,并在请求正文中添加“ image / jpeg”。 Here is the corrected code.. 这是更正的代码。

OkHttpClient client = new OkHttpClient();
            RequestBody body = RequestBody.create(MediaType.parse("image/jpeg"), file); //Here is the change with parsed value and file should be a byte[]
            Request request = new Request.Builder()
                    .url("https://www.googleapis.com/upload/drive/v3/files?uploadType=media")
                    .addHeader("Content-Type", "application/json") //Here is the change
                    .addHeader("Content-Length", "36966.4")
                    .addHeader("Authorization", String.format("Bearer %s", accessToken))
                    .post(body)
                    .build();
            Response response = null;
            try {
                response = client.newCall(request).execute();
                successCode = String.valueOf(response.code());
            }catch (IOException e){
                e.printStackTrace();
            }

I would like to mention one more thing that is related to OAuth 2.0 authorization. 我想提一提与OAuth 2.0授权有关的另一件事。 As per Google guidance I have used the code from Codelab. 根据Google的指导,我使用了Codelab的代码。 Here is the link to get the code https://codelabs.developers.google.com/codelabs/appauth-android-codelab/?refresh=1#0 The scope should be the API provided by the Google for that particular service. 这是获取代码的链接https://codelabs.developers.google.com/codelabs/appauth-android-codelab/?refresh=1#0范围应为Google为该特定服务提供的API。 For me it is " https://www.googleapis.com/auth/drive.file ". 对我而言,它是“ https://www.googleapis.com/auth/drive.file ”。

But still I stuck with the filename in the drive end. 但是我仍然坚持使用驱动器端的文件名。 Its saving the files with a name "Untitled". 它以“无标题”名称保存文件。 Could you please help me on that? 你能帮我吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM