后端(4)-springboot返回二进制流报错

7 阅读1分钟

后端原本代码

// controller中ApiResponse是接口返回的统一数据模型,其中data返回字节数组
public ResponseEntity<ApiResponse<byte[]>> requestTextToAudio(@RequestParam("text") String text) {

// headers设置contentType为字节流,这里导致了下面的报错
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);

报错如下

Exception: No converter for [class com.money.aiaudioservice.response.ApiResponse] with preset Content-Type 'application/octet-stream'

大意是无法解析application/octet-stream

原因

因为 Spring Boot 在处理响应时,找不到合适的消息转换器将 ApiResponse 对象转换为 application/octet-stream 类型的响应。下面详细分析可能的原因并给出相应的解决办法。

返回的Gson格式中包裹了byte[]二进制流导致无法解析

解决方案

将返回的二进制流改成用base64编码的字符串,客户端调用接口后再将字符串转换成bytes[]字节流,再保存为文件即可。

springboot核心代码如下:

byteBuffer = convertTextToAudio(text);
// 将 ByteBuffer 转换为字节数组
byte[] bytes = new byte[byteBuffer.remaining()];
byteBuffer.get(bytes);

//将原本的bytes[]转换成Base64编码字符串
String base64AudioData = Base64.getEncoder().encodeToString(bytes);

// 创建统一返回对象,返回数据模型ApiResponse中改为传base64编码的字符串
ApiResponse<String> apiResponse = new ApiResponse<>(200, "File download success", base64AudioData);

// 设置响应头,响应头从APPLICATION_OCTET_STREAM改为APPLICATION_JSON
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// springboot不需要设置contentLength,会自动计算并返回

客户端修改后的核心代码如下:

// ApiService中返回数据模型ApiResponse<String>中data为string
suspend fun requestTextToAudio(@Query("text") text: String): Response<ApiResponse<String>>

// 返回的data为base64编码,这里解码为ByteArray格式
val result = withContext(Dispatchers.IO) {
    val audioData = android.util.Base64.decode(response.data, android.util.Base64.DEFAULT)
    repository.saveAudioFile(text, audioData)
}

// 保存字节流为文件
suspend fun saveAudioFile(text:String, audioData: ByteArray):String? {
    var outputStream: FileOutputStream? = null
    try {
        val relativePath = "aiAudio/" + FileNameFormatUtil.convertToValidFileName(text, MAX_FILE_LENGTH) + MP3_FILE
        val file = File(application.filesDir, relativePath)
        FileUtils.createFileDirs("aiAudio")
        outputStream = FileOutputStream(file)
        outputStream.write(audioData)
        return file.absolutePath
    } catch (e: IOException) {
        e.printStackTrace()
    } finally {
        outputStream?.close()
    }
    return null
}