最近开发的一款app有使用百度人工智能图像方面的api,但由于个人的疏忽,导致部分问题排查了很久才发现,于此记录
okhttp3.internal.http2.StreamResetException: stream was reset: CANCEL
- 正常使用
retrofit2调用接口的时候出现问题,本来以为是base64转码后编码长度过大,后来发现没到1M还是报错,经过层层排查,发现在发起请求的Service部分我写成了
package com.ericmoin.myapplication
import retrofit2.Call
import retrofit2.http.Header
import retrofit2.http.Headers
import retrofit2.http.POST
import retrofit2.http.Path
import retrofit2.http.Query
interface ImageService {
@Headers(
"Content-Type:application/x-www-form-urlencoded",
"Accept:application/json"
)
@POST("contrast_enhance?access_token=${Constants.ACCESS_TOKEN}")
fun contrastEnhanceByImage( @Query("image") image:String ): Call<ImageResponse>
}
@Query注解用习惯了,一直以为在URL后诸如image=xxx的参数都用@Query的形式标注。事实上百度在请求头部分已经说明x-www-form-urlencoded表示其后的参数要以表单数据的形式提交,正确写法应为
package com.ericmoin.myapplication
import retrofit2.Call
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.Header
import retrofit2.http.Headers
import retrofit2.http.POST
import retrofit2.http.Path
import retrofit2.http.Query
interface ImageService {
@FormUrlEncoded
@Headers(
"Content-Type:application/x-www-form-urlencoded",
"Accept:application/json"
)
@POST("contrast_enhance?access_token=${Constants.ACCESS_TOKEN}")
fun contrastEnhanceByImage( @Field("image") image:String ): Call<ImageResponse>
}
base64转码
- 百度的
api需要将图片转成base64编码,在app内展示的时候我已经有了一个bitmap,想着用已经展示的bitmap直接转码,结果发现报OOM异常,代码如下
suspend fun convertBitmap2String(
bitmap: Bitmap,
format: Bitmap.CompressFormat = Bitmap.CompressFormat.JPEG,
quality: Int = 100
) = withContext(Dispatchers.IO){
ByteArrayOutputStream().use { outputStream ->
bitmap.compress(format, quality, outputStream)
val buffer = outputStream.toByteArray()
Base64.encodeToString(buffer, Base64.DEFAULT)
}
}
suspend fun convertString2Bitmap(bitmapStr: String): Bitmap {
val result = CoroutineScope(Dispatchers.IO).async {
val byteArray = Base64.decode(bitmapStr, Base64.DEFAULT)
BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
}
return result.await()
}
- 想到可能是一次分配的空间太多了,而且在运行过程中
JVM一直在启动GC。苦思冥想许久找不到结果,最后百度的文档中提供了一个直接转化文件的方法
fun getFileContentAsBase64(path: String, urlEncode: Boolean = true): String {
val b = Files.readAllBytes(Paths.get(path))
var base64 = java.util.Base64.getEncoder().encodeToString(b)
if (urlEncode) {
base64 = URLEncoder.encode(base64, "utf-8")
}
return base64
}
- 需要注意,如果在
Android中作为工具类的方法使用,需要保证你的minSdk >= 26