我在浏览器中处理一个项目,该项目从服务器接收多部分响应。
响应的第一部分是一些JSON元数据
响应的第二部分是二进制MP3文件。
我需要一种从多部分响应中提取该MP3文件并在HTML 5音频元素中播放的方法。
有没有人遇到这个或类似的东西?
答案 0 :(得分:1)
我最终解决了我的问题。我为将来需要这样做的人提供了问题和解决方案。
背景信息:
我在制作这个ajax请求时使用AngularJS,但对于jquery ajax和常规xhr这个想法都是一样的。
<强>代码:强>
//creating a form object and assigning everything
//to it is so that XHR can automatically
//generate proper multipart formatting
var form = new FormData();
var data = {};
data['messageHeader'] = {};
var jsonData = JSON.stringify(data);
var jsonBlob = new Blob([jsonData],{type: "application/json"});
//assign json metadata blob and audio blob to the form
form.append("request", jsonData);
form.append("audio",response); //Response is the audio blob
//make the post request
//Notes:
//content-type set to undefined so angular can auto assign type
//transformRequest: angular.identity allows for angular to create multipart
//response: arraybuffer so untouched binary data can be received
$http({method:"POST",
url: endpoint + path,
headers: {
'Authorization': 'Bearer ' + $cookies.get('token'),
'Content-Type': undefined
},
transformRequest: angular.identity,
data: form,
responseType: "arraybuffer"
})
.success(function(data){
//data: ArrayBuffer of multipart response
//toss ArrayBuffer into Uint8Array
//lets you iterate over the bytes
var audioArray = new Uint8Array(data);
//toss a UTF-8 version of the response into
//a variable. Used to extract metadata
var holder = "";
for (var i = 0; i < audioArray.length; i++){
holder += String.fromCharCode(audioArray[i]);
}
//get the boundary from the string. Eg contents of first line
var boundary = holder.substr(0, holder.indexOf("\n"));
//break response into array at each boundary string
var temp = holder.split(boundary);
var parts = [];
//loop through array to remove empty parts
for (var i = 0; i < temp.length; i++){
if (temp[i] != ""){
parts.push(temp[i]);
}
}
//PARSE FIRST PART
//get index of first squiggly, indicator of start of JSON
var jsonStart = parts[0].indexOf('{');
//string to JSON on { index to end of part substring
var JSONResponse = JSON.parse(parts[0].substring(jsonStart));
//PARSE SECOND PART
var audioStart = holder.indexOf('mpeg') + 8;
//get an ArrayBuffer from UInt8Buffer from the audio
//start point to the end of the array
var audio = audioArray.buffer.slice(audioStart);
//hand off audio to AudioContext for automatic decoding
audio_context.decodeAudioData(audio, function(buffer) {
var audioBuffer = buffer;
//create a sound source
var source = audio_context.createBufferSource();
//attach audioBuffer to sound source
source.buffer = audioBuffer;
//wire source to speakers
source.connect(audio_context.destination);
//on audio completion, re-enable mic button
source.onended = function() {
console.log("ended");
$scope.$apply(function(){
$scope.playing = false;
});
}
//start playing audio
source.start(0);
}, function (){
//callback for when there is an error
console.log("error decoding audio");
});
})
&#13;
<强>概述:强>
您需要接受响应为纯二进制数据(ArrayBuffer)。大多数库都会将它作为字符串提供给您,这对于正常请求来说很酷,但对于二进制数据却很糟糕。
然后逐步浏览数据以查找多部分边界。
然后你在边界处分开。
获取您知道的边界索引是二进制数据
然后从ArrayBuffer中检索原始二进制文件。
在我的情况下,我将该二进制文件发送到扬声器,但是如果它是一个图像,您可以构建一个blob,从FileReader获取一个URL,然后将其设置为图像的源。