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

如何使用完整端点URL发起Retrofit POST请求,解决URL格式报错?

问题描述

我需要通过Retrofit发送POST请求,但该请求的完整端点URL(示例:https://pod-000-1005-03.backblaze.com/b2api/v2/b2_upload_file?cvt=c001_v0001005_t0027&bucket=4a48fe8875c6214145260818)来自另一个GET请求。当前创建Retrofit实例的代码因该URL未以‘/’结尾抛出异常,请问如何直接向该端点发起请求?

现有代码

创建Retrofit实例的代码

fun getUploadApi(uploadUrl: String): B2UploadApi {
        return Retrofit.Builder()
            .baseUrl(uploadUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(B2UploadApi::class.java)
    }
  • 此代码抛出异常,原因是URL未以‘/’结尾

POST请求接口代码

@POST
    suspend fun uploadFile(
        @Header("Authorization") authToken: String,
        @Header("X-Bz-File-Name") fileName: String,
        @Header("Content-Length") fileSize: Int,
        @Header("Content-Type") mimeType: String,
        @Header("X-Bz-Content-Sha1") sha1: String,
        @Body byteArray: ByteArray
    ): Response<UploadResponse>
解决方案

有两种实用的解决方式:

方式一:用@Url注解传递完整URL(推荐)

不用为每个动态URL创建新Retrofit实例,直接在接口方法里通过@Url接收完整上传URL,Retrofit实例用一个格式合法的通用baseUrl即可。

修改后的接口代码:

@POST
suspend fun uploadFile(
    @Url uploadUrl: String,
    @Header("Authorization") authToken: String,
    @Header("X-Bz-File-Name") fileName: String,
    @Header("Content-Length") fileSize: Int,
    @Header("Content-Type") mimeType: String,
    @Header("X-Bz-Content-Sha1") sha1: String,
    @Body byteArray: ByteArray
): Response<UploadResponse>

复用全局Retrofit实例的代码:

fun getGlobalApi(): B2UploadApi {
    return Retrofit.Builder()
        .baseUrl("https://any-valid-domain.com/") // 只要是带/结尾的合法URL就行
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(B2UploadApi::class.java)
}

调用时直接传入从GET请求拿到的完整URL即可,这种方式避免频繁创建Retrofit实例,更高效。

方式二:处理动态URL格式并拆分参数

如果坚持要为每个URL创建Retrofit实例,可以先处理传入的uploadUrl,确保baseUrl以/结尾,同时剥离查询参数单独添加到请求中(Retrofit的baseUrl不应该包含查询参数)。

处理URL的代码示例:

fun getUploadApi(uploadUrl: String): B2UploadApi {
    val url = URL(uploadUrl)
    // 构建不带查询参数的baseUrl,确保以/结尾
    val baseUrl = "${url.protocol}://${url.host}${url.path}".let {
        if (it.endsWith("/")) it else "$it/"
    }
    return Retrofit.Builder()
        .baseUrl(baseUrl)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(B2UploadApi::class.java)
}

同时修改接口添加查询参数:

@POST
suspend fun uploadFile(
    @Header("Authorization") authToken: String,
    @Header("X-Bz-File-Name") fileName: String,
    @Header("Content-Length") fileSize: Int,
    @Header("Content-Type") mimeType: String,
    @Header("X-Bz-Content-Sha1") sha1: String,
    @Query("cvt") cvt: String,
    @Query("bucket") bucket: String,
    @Body byteArray: ByteArray
): Response<UploadResponse>

这种方式需要拆分URL路径和参数,相对繁琐,优先推荐第一种方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 09:06:37