我缺少将网络浏览器中录制的长音频发送到 oracle apex 的东西吗?
I'm missing something to send long audios recorded in the web browser to oracle apex?
我正在尝试将录制的音频从 Web 浏览器发送到 Oracle Apex,但当音频很长时出现问题。当音频少于两分钟时,代码运行良好。
据我所知,数据是由 URL 发送的,因此是以文本格式发送的。 Oracle 对字符串有 32k 的限制,因此如果 blob 超过该限制,则必须将其发送到一个数组中,每个数组分成 30k 的部分。所以我怀疑数组没有以正确的格式发送,但我不知道如何确认它。
我使用的代码如下:(我为Apex构建了一个插件来发送音频)
- Javascript 中发送音频的片段:
// builds a js array from long string
clob2Array: function(clob, size, array) {
loopCount = Math.floor(clob.length / size) + 1;
for (var i = 0; i < loopCount; i++) {
array.push(clob.slice(size * i, size * (i + 1)));
}
return array;
},
// converts DataURI to base64 string
dataURI2base64: function(dataURI) {
var base64 = dataURI.substr(dataURI.indexOf(',') + 1);
return base64;
},
blobToDataURL: function(blob, callback) {
var a = new FileReader();
a.onload = function(e) {callback(e.target.result);}
a.readAsDataURL(blob);
},
// save to DB function
save2Db: function(pAjaxIdentifier, pRegionId, pAudio, callback) {
apexAudio.blobToDataURL(pAudio, function(data){
// audio DataURI to base64
var base64 = apexAudio.dataURI2base64(data);
// split base64 clob string to f01 array length 30k
var f01Array = new Array();
f01Array = apexAudio.clob2Array(base64, 30000, f01Array);
// Apex Ajax Call
apex.server.plugin(pAjaxIdentifier, {
f01: f01Array,
}, {
dataType: 'html',
// SUCESS function
success: function() {
// add apex event
$('#' + pRegionId).trigger('apexaudio-saved-db');
// callback
callback();
},
// ERROR function
error: function(xhr, pMessage) {
// add apex event
$('#' + pRegionId).trigger('apexaudio-error-db');
console.log('save2Db: apex.server.plugin ERROR:', pMessage);
// callback
callback();
}
});
});
}
- 接收adn的PL/SQL代码将字符串数组转化为blob
DECLARE
--
l_collection_name VARCHAR2(100);
l_blob BLOB;
l_filename VARCHAR2(100);
l_mime_type VARCHAR2(100);
l_token VARCHAR2(32000);
--
BEGIN
-- get defaults
l_filename := 'audio_' || to_char(SYSDATE, 'YYYYMMDDHH24MISS') || '.webm';
l_mime_type := 'audio/webm';
-- build BLOB from f01 30k Array
dbms_lob.createtemporary(l_blob,
TRUE,
dbms_lob.session);
FOR i IN 1 .. apex_application.g_f01.count LOOP
l_token := wwv_flow.g_f01(i);
IF length(l_token) > 0 THEN
dbms_lob.append(l_blob
,to_blob(utl_encode.base64_decode(utl_raw.cast_to_raw(l_token))));
END IF;
END LOOP;
l_collection_name := 'APEX_AUDIO';
APEX_COLLECTION.CREATE_OR_TRUNCATE_COLLECTION(
p_collection_name => l_collection_name);
-- add collection member (only if BLOB not null)
IF dbms_lob.getlength(l_blob) IS NOT NULL THEN
apex_collection.add_member(p_collection_name => l_collection_name,
p_c001 => l_filename, -- filename
p_c002 => l_mime_type, -- mime_type
p_d001 => SYSDATE, -- date created
p_blob001 => l_blob); -- BLOB audio content
END IF;
END;
我再说一遍,如果音频很短,代码可以完美运行,但如果很长,就会出现以下错误:
2020-02-20T20:09:27.169Z SEVERE <P-fvMwI2WpKybDySZRumRQ> java.sql.SQLException: ORA-06550: line 2, column 2:
PLS-00306: number or wrong type arguments when calling 'AJAX'
ORA-06550: line 2, column 2:
PL/SQL: Statement ignored
InternalServerException [statusCode=500, reasons=[]]
at oracle.dbtools.apex.ModApexContext.handleError(ModApexContext.java:288)
at oracle.dbtools.apex.OWA.execute(OWA.java:206)
at oracle.dbtools.apex.ModApex.handleRequest(ModApex.java:310)
at oracle.dbtools.apex.ModApex.doPost(ModApex.java:188)
at oracle.dbtools.apex.ModApex.service(ModApex.java:112)
at oracle.dbtools.http.entrypoint.Dispatcher.dispatch(Dispatcher.java:126)
[...]
技术:
- 甲骨文 12c
- 甲骨文顶点 19.2
- 订单 19.4
- Tomcat 8
因此您使用 AJAX 发送请求,内容类型为 "application/x-www-form-urlencoded" Tomcat 限制了允许的最大 POST 大小(默认为 2MB)。
要使其在 APEX 中工作,您可能有 2 种方法
1) 进行某种双分块上传,因此首先将文件本身拆分为例如file.slice() 然后构建每个文件块的 30k base64 数组并逐块上传
2) 在表单提交中使用 "multipart/form-data" 内容类型,因此您在 Tomcat 的 2MB 限制中没有 运行。
前段时间做了一个文件上传插件,看看这个功能:
上传的文件会自动插入apex_application_files,你可以从那里抓取它:
当您可以在 APEX 应用程序内部执行此操作时,我不建议使用 ORDS 执行此操作,因此您必须处理安全性、额外的身份验证等问题...
我正在尝试将录制的音频从 Web 浏览器发送到 Oracle Apex,但当音频很长时出现问题。当音频少于两分钟时,代码运行良好。
据我所知,数据是由 URL 发送的,因此是以文本格式发送的。 Oracle 对字符串有 32k 的限制,因此如果 blob 超过该限制,则必须将其发送到一个数组中,每个数组分成 30k 的部分。所以我怀疑数组没有以正确的格式发送,但我不知道如何确认它。
我使用的代码如下:(我为Apex构建了一个插件来发送音频)
- Javascript 中发送音频的片段:
// builds a js array from long string
clob2Array: function(clob, size, array) {
loopCount = Math.floor(clob.length / size) + 1;
for (var i = 0; i < loopCount; i++) {
array.push(clob.slice(size * i, size * (i + 1)));
}
return array;
},
// converts DataURI to base64 string
dataURI2base64: function(dataURI) {
var base64 = dataURI.substr(dataURI.indexOf(',') + 1);
return base64;
},
blobToDataURL: function(blob, callback) {
var a = new FileReader();
a.onload = function(e) {callback(e.target.result);}
a.readAsDataURL(blob);
},
// save to DB function
save2Db: function(pAjaxIdentifier, pRegionId, pAudio, callback) {
apexAudio.blobToDataURL(pAudio, function(data){
// audio DataURI to base64
var base64 = apexAudio.dataURI2base64(data);
// split base64 clob string to f01 array length 30k
var f01Array = new Array();
f01Array = apexAudio.clob2Array(base64, 30000, f01Array);
// Apex Ajax Call
apex.server.plugin(pAjaxIdentifier, {
f01: f01Array,
}, {
dataType: 'html',
// SUCESS function
success: function() {
// add apex event
$('#' + pRegionId).trigger('apexaudio-saved-db');
// callback
callback();
},
// ERROR function
error: function(xhr, pMessage) {
// add apex event
$('#' + pRegionId).trigger('apexaudio-error-db');
console.log('save2Db: apex.server.plugin ERROR:', pMessage);
// callback
callback();
}
});
});
}
- 接收adn的PL/SQL代码将字符串数组转化为blob
DECLARE
--
l_collection_name VARCHAR2(100);
l_blob BLOB;
l_filename VARCHAR2(100);
l_mime_type VARCHAR2(100);
l_token VARCHAR2(32000);
--
BEGIN
-- get defaults
l_filename := 'audio_' || to_char(SYSDATE, 'YYYYMMDDHH24MISS') || '.webm';
l_mime_type := 'audio/webm';
-- build BLOB from f01 30k Array
dbms_lob.createtemporary(l_blob,
TRUE,
dbms_lob.session);
FOR i IN 1 .. apex_application.g_f01.count LOOP
l_token := wwv_flow.g_f01(i);
IF length(l_token) > 0 THEN
dbms_lob.append(l_blob
,to_blob(utl_encode.base64_decode(utl_raw.cast_to_raw(l_token))));
END IF;
END LOOP;
l_collection_name := 'APEX_AUDIO';
APEX_COLLECTION.CREATE_OR_TRUNCATE_COLLECTION(
p_collection_name => l_collection_name);
-- add collection member (only if BLOB not null)
IF dbms_lob.getlength(l_blob) IS NOT NULL THEN
apex_collection.add_member(p_collection_name => l_collection_name,
p_c001 => l_filename, -- filename
p_c002 => l_mime_type, -- mime_type
p_d001 => SYSDATE, -- date created
p_blob001 => l_blob); -- BLOB audio content
END IF;
END;
我再说一遍,如果音频很短,代码可以完美运行,但如果很长,就会出现以下错误:
2020-02-20T20:09:27.169Z SEVERE <P-fvMwI2WpKybDySZRumRQ> java.sql.SQLException: ORA-06550: line 2, column 2:
PLS-00306: number or wrong type arguments when calling 'AJAX'
ORA-06550: line 2, column 2:
PL/SQL: Statement ignored
InternalServerException [statusCode=500, reasons=[]]
at oracle.dbtools.apex.ModApexContext.handleError(ModApexContext.java:288)
at oracle.dbtools.apex.OWA.execute(OWA.java:206)
at oracle.dbtools.apex.ModApex.handleRequest(ModApex.java:310)
at oracle.dbtools.apex.ModApex.doPost(ModApex.java:188)
at oracle.dbtools.apex.ModApex.service(ModApex.java:112)
at oracle.dbtools.http.entrypoint.Dispatcher.dispatch(Dispatcher.java:126)
[...]
技术:
- 甲骨文 12c
- 甲骨文顶点 19.2
- 订单 19.4
- Tomcat 8
因此您使用 AJAX 发送请求,内容类型为 "application/x-www-form-urlencoded" Tomcat 限制了允许的最大 POST 大小(默认为 2MB)。 要使其在 APEX 中工作,您可能有 2 种方法
1) 进行某种双分块上传,因此首先将文件本身拆分为例如file.slice() 然后构建每个文件块的 30k base64 数组并逐块上传
2) 在表单提交中使用 "multipart/form-data" 内容类型,因此您在 Tomcat 的 2MB 限制中没有 运行。
前段时间做了一个文件上传插件,看看这个功能:
上传的文件会自动插入apex_application_files,你可以从那里抓取它:
当您可以在 APEX 应用程序内部执行此操作时,我不建议使用 ORDS 执行此操作,因此您必须处理安全性、额外的身份验证等问题...