如何使用完整端点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
相关产品推荐
相关产品推荐

