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

使用Ktor 2.3.3(Kotlin)拉取Azure工作项遇401未授权问题求助

问题分析与解决方案

你的问题出在Authorization请求头的构造方式错误,Azure DevOps的Basic认证要求将: + PAT令牌的字符串整体进行Base64编码,而非分开编码后拼接。

错误点说明

你当前的代码分别对:和PAT令牌做Base64编码再拼接,这会生成不符合要求的认证字符串,直接导致401 Unauthorized:

"Basic ${Base64.getEncoder().encodeToString(":".toByteArray())}${Base64.getEncoder().encodeToString(patToken.toByteArray())}"

修正后的代码

import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.request.*
import io.ktor.serialization.kotlinx.json.*
import java.util.*

object AzureDevOpsClient {
    private const val BASE_URL = "https://mydevops.com" // 补充完整协议头https://
    private const val API_VERSION = "6.0"

    private val client = HttpClient() {
        install(ContentNegotiation) {
           json()
        }
    }

    suspend fun getWorkItems(patToken: String, ids: List<Int>): String {
        val url = "$BASE_URL?ids=${ids.joinToString(",")}&api-version=$API_VERSION"
        // 正确构造:将":PAT令牌"整体做Base64编码
        val authToken = Base64.getEncoder().encodeToString(":$patToken".toByteArray(Charsets.UTF_8))

        return client.get(url) {
            header("Authorization", "Basic $authToken")
        }.body<String>()
    }
}

额外注意事项

  • 确保BASE_URL包含完整协议头(如https://),否则Ktor无法正确解析请求地址。
  • 可添加错误处理逻辑,方便调试认证问题:
    import io.ktor.client.statement.*
    import io.ktor.http.*
    
    // 修改getWorkItems函数
    val response = client.get(url) {
        header("Authorization", "Basic $authToken")
    }
    if (response.status == HttpStatusCode.Unauthorized) {
        throw IllegalStateException("认证失败,请检查PAT令牌权限或有效性")
    }
    return response.body<String>()
    
  • 确认PAT令牌拥有Work Items读取权限,且未过期。

内容的提问来源于stack exchange,提问作者Kerry

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 06:11:28