用 curl 正常
curl -X POST 'https://xxx/audio-to-text' --header 'Authorization: xxx' --form 'file=@xxx/1.mp3;type=audio/mp3'
小程序: 一直 415
对了半天: mine-type
不一样。
wx.uploadFile
不支持 mine-type
,让 ai 重新写了,终于解决了。
cv 给 ai,让 ai 参考就行
// 修复的方案 2:正确处理二进制文件数据
(async function testAudioAPIFixed() {
console.log('=== 修复的手动构造 multipart 测试 ===')
const audioUrl = 'xxx/1.mp3'
const apiConfig = {
baseUrl: 'https://xxx/v1',
apiKey: 'xxxx'
}
try {
// 下载文件
const downloadResult = await new Promise((resolve, reject) => {
wx.downloadFile({
url: audioUrl,
success: resolve,
fail: reject
})
})
// 读取文件数据为 ArrayBuffer
const fileData = await new Promise((resolve, reject) => {
wx.getFileSystemManager().readFile({
filePath: downloadResult.tempFilePath,
success: resolve,
fail: reject
})
})
console.log('文件读取成功,大小:', fileData.data.byteLength)
// 手动构造 multipart/form-data - 正确处理二进制数据
const boundary = '----formdata-' + Date.now()
const encoder = new TextEncoder()
// 构造表单头部(文本部分)
let formHeader = ''
formHeader += `--${boundary}\r\n`
formHeader += `Content-Disposition: form-data; name="file"; filename="1.mp3"\r\n`
formHeader += `Content-Type: audio/mp3\r\n\r\n` // ✅ 关键:设置正确的 MIME 类型
// 构造表单尾部(文本部分)
const formFooter = `\r\n--${boundary}--\r\n`
// 转换文本部分为 ArrayBuffer
const headerBuffer = encoder.encode(formHeader)
const footerBuffer = encoder.encode(formFooter)
// 组合所有数据:头部 + 文件数据 + 尾部
const totalLength = headerBuffer.byteLength + fileData.data.byteLength + footerBuffer.byteLength
const finalBuffer = new ArrayBuffer(totalLength)
const finalView = new Uint8Array(finalBuffer)
let offset = 0
// 复制头部
finalView.set(new Uint8Array(headerBuffer), offset)
offset += headerBuffer.byteLength
// 复制文件数据(保持原始二进制格式)
finalView.set(new Uint8Array(fileData.data), offset)
offset += fileData.data.byteLength
// 复制尾部
finalView.set(new Uint8Array(footerBuffer), offset)
console.log('multipart 数据组装完成,总大小:', finalBuffer.byteLength)
// 发送请求
const result = await new Promise((resolve, reject) => {
wx.request({
url: `${apiConfig.baseUrl}/audio-to-text`,
method: 'POST',
header: {
'Authorization': `Bearer ${apiConfig.apiKey}`,
'Content-Type': `multipart/form-data; boundary=${boundary}`
},
data: finalBuffer, // ✅ 发送完整的 ArrayBuffer
success: resolve,
fail: reject
})
})
console.log('修复版 multipart 结果:', result)
if (result.statusCode === 200) {
const responseData = typeof result.data === 'string' ? JSON.parse(result.data) : result.data
console.log('✅ 成功!', responseData)
wx.showModal({
title: '修复版 multipart 成功',
content: `识别结果: ${responseData.text}`,
showCancel: false
})
} else {
console.error('❌ 失败:', result.statusCode, result.data)
wx.showModal({
title: '修复版 multipart 失败',
content: `状态码: ${result.statusCode}\n 错误: ${result.data}`,
showCancel: false
})
}
} catch (error) {
console.error('❌ 修复版 multipart 错误:', error)
wx.showModal({
title: '修复版 multipart 异常',
content: error.message,
showCancel: false
})
}
})()