2

我正在尝试将录制的音频从 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
  • 雄猫 8
4

1 回答 1

3

因此,您使用内容类型为“application/x-www-form-urlencoded”的 AJAX 发送请求,Tomcat 限制了允许的最大 POST 大小(默认为 2MB)。要使其在 APEX 中工作,您可能有两种方法

1)做某种双分块上传,所以首先你用例如file.slice()分割文件本身,然后你构建每个文件块的30k base64数组并逐块上传

2) 使用带有表单提交的“multipart/form-data”内容类型,因此这里您没有在 Tomcat 的 2MB 限制中运行。

我前段时间建了一个文件上传插件,看看这个功能:

https://github.com/Dani3lSun/apex-plugin-dropzone/blob/90a82f4bb83fee9d78458af790560fb6c5b77978/server/js/apexdropzone.js#L378

上传的文件将自动插入到 apex_application_files 中,您可以从那里获取它:

https://github.com/Dani3lSun/apex-plugin-dropzone/blob/90a82f4bb83fee9d78458af790560fb6c5b77978/source/render_region.sql#L332

当您可以在 APEX 应用程序中执行此操作时,我不建议您使用 ORDS 执行此操作,因此您必须处理安全性、附加身份验证等问题......

于 2020-02-21T21:16:48.957 回答