You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin服务端应用使用Google Drive服务账号认证上传文件时遭遇401 Unauthorized错误及相关优化需求

Kotlin服务端应用使用Google Drive服务账号认证上传文件时遭遇401 Unauthorized错误及相关优化需求

嗨,我来帮你一步步解决这个问题,同时满足你对API升级和序列化方式的需求:

一、先搞定401 Unauthorized的核心问题

你遇到的401错误主要有两个关键原因,咱们逐一排查解决:

1. 服务账号缺少写入权限的Scope

你的旧代码能读取目录是因为用了drive.readonly的Scope,但上传文件需要写入权限。你第一份代码里的GoogleCredentials没有指定Scope,默认权限不足,所以要明确添加写入相关的Scope:

val credentials = GoogleCredentials.fromStream(FileInputStream("gdrive-admin.json"))
    .createScoped(listOf("https://www.googleapis.com/auth/drive")) // 全权限,也可以用drive.file更细粒度

如果你不想给全权限,可以用https://www.googleapis.com/auth/drive.file,但需要确保上传目标文件夹已经共享给服务账号邮箱。

2. 服务账号的文件存储位置问题

服务账号有自己独立的云端硬盘空间,你共享给它的文件夹需要明确指定为上传文件的父目录,否则文件会上传到服务账号自己的盘里(你看不到,但其实可能上传成功了)。修改文件元数据,添加父文件夹ID:

val fileMetadata = File()
fileMetadata.setName("img3.jpg")
fileMetadata.parents = listOf("你的共享文件夹ID") // 替换成你实际共享的文件夹ID

二、替换已废弃的GoogleCredential

你提到GoogleCredential已经被废弃,现在官方推荐使用GoogleCredentials(就是你第一份代码里的类),结合上面的Scope配置,就能替代旧代码的功能,同时避免废弃API的警告。

三、切换到Kotlin Serialization替代Gson

要替换GsonFactory为Kotlin Serialization,需要做以下几步:

1. 添加依赖

在你的build.gradle.kts(或build.gradle)里添加Google API Client对Kotlin Serialization的支持:

// Gradle Kotlin DSL示例
implementation("com.google.api-client:google-api-client-kotlin-serialization:1.44.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0") // 确保序列化核心库版本匹配

同时要确保已经启用Kotlin Serialization插件:

plugins {
    kotlin("jvm") version "1.9.0"
    kotlin("plugin.serialization") version "1.9.0"
}

2. 修改代码中的JsonFactory

把GsonFactory.getDefaultInstance()替换为KotlinSerializationJsonFactory:

import com.google.api.client.json.kotlin.KotlinSerializationJsonFactory

// ...

val jsonFactory = KotlinSerializationJsonFactory()
val service = Drive.Builder(NetHttpTransport(), jsonFactory, requestInitializer)
    .setApplicationName("Drive samples").build()

整合后的完整可运行代码

把以上修改整合到一起,最终的上传代码应该是这样的:

import com.google.api.client.googleapis.auth.oauth2.GoogleCredentials
import com.google.api.client.http.HttpCredentialsAdapter
import com.google.api.client.http.javanet.NetHttpTransport
import com.google.api.client.json.kotlin.KotlinSerializationJsonFactory
import com.google.api.services.drive.Drive
import com.google.api.services.drive.model.File
import com.google.api.services.drive.model.FileContent
import java.io.FileInputStream

fun uploadBasic(): String? {
    // 加载服务账号凭证并添加写入权限Scope
    val credentials = GoogleCredentials.fromStream(FileInputStream("gdrive-admin.json"))
        .createScoped(listOf("https://www.googleapis.com/auth/drive"))

    val requestInitializer = HttpCredentialsAdapter(credentials)

    // 使用Kotlin Serialization构建Drive服务
    val service = Drive.Builder(NetHttpTransport(), KotlinSerializationJsonFactory(), requestInitializer)
        .setApplicationName("Drive samples").build()

    // 配置文件元数据,指定上传到共享文件夹
    val fileMetadata = File()
    fileMetadata.setName("img3.jpg")
    fileMetadata.parents = listOf("替换为你的共享文件夹ID") // 这里要填实际的文件夹ID

    // 指定文件类型和路径
    val mediaContent = FileContent("image/jpeg", java.io.File("images/img3.jpg"))

    return try {
        val file = service.files().create(fileMetadata, mediaContent).setFields("id").execute()
        println("File ID: " + file.id)
        file.id
    } catch (e: com.google.api.client.googleapis.json.GoogleJsonResponseException) {
        System.err.println("Unable to upload file: " + e.details)
        throw e
    }
}

额外注意点

  • 共享文件夹给服务账号时,要确保服务账号的邮箱(在gdrive-admin.json里的client_email字段)被添加为文件夹的编辑者或所有者。
  • 如果用drive.file的Scope,上传前需要确保服务账号已经有该文件夹的访问权限(通过共享操作),否则还是会报错。

备注:内容来源于stack exchange,提问作者Psijic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 11:09:38