Home >Backend Development >Golang >File upload to Google Drive via API fails

File upload to Google Drive via API fails

王林
王林forward
2024-02-09 13:30:08464browse

通过 API 将文件上传到 Google Drive 失败

php editor Xigua tells you that sometimes we may encounter failures when using the API to upload files to Google Drive. This situation may be caused by various reasons, such as network problems, insufficient permissions, etc. But don’t worry, there are some things we can do to fix this problem. Next, we will introduce in detail how to successfully upload files to Google Drive through the API, so that everyone will no longer worry about this problem.

Question content

I'm trying to upload a file to my Google Drive but it's failing. I thought I had specified the MIME type correctly because I found this to be a common problem, but it still doesn't work for me.

About the conversion system: I have an API for Gin-Gonic (v1.9.1) where I can upload files. The file is successfully passed from the frontend/postman to the API as I can successfully save the file I got from the API.

The error I get is:

Post "https://www.googleapis.com/upload/drive/v3/files?alt=json&prettyPrint=false&uploadType=multipart": Post "": unsupported protocol scheme ""

I have the following function:

func (c *Client) UploadFile(oauthTokenConfig GoogleOauthTokenConfig, parentFolderId string, fileHeader *multipart.FileHeader) (*string, error) {
    svc, err := drive.NewService(context.Background(), option.WithHTTPClient(
        oauthTokenConfig.Config.Client(
            context.Background(),
            &oauth2.Token{
                AccessToken:  oauthTokenConfig.AccessToken,
                TokenType:    oauthTokenConfig.TokenType,
                RefreshToken: oauthTokenConfig.RefreshToken,
                Expiry:       oauthTokenConfig.ExpiresIn,
            },
        )),
    )
    if err != nil {
        return nil, err
    }

    fileExtension := filepath.Ext(fileHeader.Filename)
    fileName := strings.TrimSuffix(fileHeader.Filename, fileExtension)
    fileMimeType := fileHeader.Header.Get("Content-Type")
    uploadFileMetaData := drive.File{
        Name:     fmt.Sprintf("%s%s", fileName, fileExtension), 
                // fmt.Sprintf("%s_%s%s", fileName, uuid.New().String(), fileExtension),
        Parents:  []string{parentFolderId},
        MimeType: fileMimeType,
    }

    file, err := fileHeader.Open()
    if err != nil {
        return nil, err
    }
    defer file.Close()

    fileResult, err := svc.Files.
        Create(&uploadFileMetaData).
        Media(file, googleapi.ContentType("text/plain")).
        Do()
    if err != nil {
        return nil, err // here I get the error
    }

        // ...

}

I added a hardcoded MIME type here, but the variable fileMimeType is actually correct. I uploaded a Test.txt file containing the contents of Test1 (which was also created successfully when I sent it via Frontend/Postman). I've also tried specifying the file MIME type dynamically or not specifying the MIME type at all, but always get the same result.

I use the following packages for this:

  • Go version: go1.21.1 darwin/arm64
  • go list -m golang.org/x/oauth2: v0.13.0
  • go list -m google.golang.org/api: v0.147.0
    • google.golang.org/api/drive/v3
    • google.golang.org/api/googleapi
    • google.golang.org/api/option

edit:

I also copied Google’s official example, but it still doesn’t work.

Workaround

Looks like the error is related to authentication. It's a bit difficult to deduce the invalid authentication from this error, but I had to change the refresh token's refresh algorithm a bit to get it to work.

This is my working code. Note that before calling the UploadFile() function, I first check oauthTokenConfig.ExpiresIn to see if the token is still valid, if so, upload the file, otherwise I first refresh the token .

File Upload

func (c *Client) UploadFile(oauthTokenConfig GoogleOauthTokenConfig, parentFolderId string, file *multipart.FileHeader) (*string, error) {
    svc, err := drive.NewService(context.Background(), option.WithHTTPClient(
        oauthTokenConfig.Config.Client(
            context.Background(),
            &oauth2.Token{
                AccessToken:  oauthTokenConfig.AccessToken,
                TokenType:    oauthTokenConfig.TokenType,
                RefreshToken: oauthTokenConfig.RefreshToken,
                Expiry:       oauthTokenConfig.ExpiresIn,
            },
        )),
    )
    if err != nil {
        return nil, fmt.Errorf("failed to create drive-service: %s", err.Error())
    }

    fileExtension := filepath.Ext(file.Filename)
    fileName := strings.TrimSuffix(file.Filename, fileExtension)
    uploadFile := drive.File{
        Name:    fmt.Sprintf("%s_%s%s", fileName, uuid.New().String(), fileExtension),
        Parents: []string{parentFolderId},
    }
    fileContent, err := file.Open()
    if err != nil {
        return nil, fmt.Errorf("failed to open file: %s", err.Error())
    }

    fileResult, err := svc.Files.Create(&uploadFile).Media(fileContent).Do()
    if err != nil {
        return nil, fmt.Errorf("failed to create file: %s", err.Error())
    }

    uploadedFile, err := svc.Files.Get(fileResult.Id).Fields("webViewLink").Do()
    if err != nil {
        return nil, fmt.Errorf("failed to get file: %s", err.Error())
    }
    return &uploadedFile.WebViewLink, nil
}

Refresh Token

func (c *Client) RefreshToken(oauthTokenConfig GoogleOauthTokenConfig) (*GoogleOauthTokenConfig, error) {
    ctx := context.Background()
    config := oauth2.Config{
        ClientID:     c.ClientId,
        ClientSecret: c.ClientSecret,
        RedirectURL:  oauthTokenConfig.Config.RedirectURL,
        Scopes:       []string{"https://www.googleapis.com/auth/drive"},
        Endpoint:     google.Endpoint,
    }

    token := &oauth2.Token{
        AccessToken:  oauthTokenConfig.AccessToken,
        TokenType:    oauthTokenConfig.TokenType,
        RefreshToken: oauthTokenConfig.RefreshToken,
        Expiry:       oauthTokenConfig.ExpiresIn,
    }

    tokenSource := config.TokenSource(ctx, token)

    updatedToken, err := tokenSource.Token()
    if err != nil {
        return nil, err
    }

    return &GoogleOauthTokenConfig{
        Config:       config,
        AccessToken:  updatedToken.AccessToken,
        RefreshToken: updatedToken.RefreshToken,
        ExpiresIn:    updatedToken.Expiry,
        TokenType:    updatedToken.TokenType,
    }, nil
}

The above is the detailed content of File upload to Google Drive via API fails. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete