You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PL/SQL中通过apex_web_service上传Blob至Alfresco服务器?

问题:Apex PL/SQL发送BLOB至Alfresco时,multipart/form-data请求报错

场景描述

在云端Apex中执行PL/SQL脚本,需从数据库表读取BLOB对象,通过带基础认证的POST请求发送到Alfresco服务器。用Postman/Insomnia发起请求的步骤为:

  • 将Content-Type设置为multipart/form-data
  • 请求体添加名为filedata的键,值选择本地文件
  • 以POST方式发送并携带基础认证信息

我的代码

尝试用APEX_WEB_SERVICE模块复现操作,编写代码如下:

DECLARE
    f_attachment BLOB;
    f_response CLOB;
    v_login VARCHAR2(100);
    v_password VARCHAR2(100);
    l_offset     INT := 1;
    p_clob CLOB;
BEGIN
    v_login := '***';
    v_password := '***';
    
    SELECT PDF INTO f_attachment FROM VIPUL_TEST WHERE ID=2;
    
    apex_web_service.g_request_headers.delete;
    apex_web_service.g_request_headers(1).name := 'Content-Type';
    apex_web_service.g_request_headers(1).value := 'multipart/form-data';
    
    f_response := apex_web_service.make_rest_request(p_url => 'https://systest.eisenvault.net/alfresco/api/-default-/public/alfresco/versions/1/nodes/2b9d7fc9-a12e-4e0b-89b2-e556ddfd2778/children',  
                                                     p_http_method => 'POST',
                                                     p_username => v_login,
                                                     p_password => v_password,
                                                     p_parm_name => apex_util.string_to_table('filedata'),
                                                     p_parm_value => apex_util.string_to_table(apex_web_service.blob2clobbase64(f_attachment))
    );
    
    -- 打印数据库取出的CLOB
    p_clob := apex_web_service.blob2clobbase64(f_attachment);
    dbms_output.put_line('Print CLOB');    
    loop  
        exit when l_offset > dbms_lob.getlength(p_clob);  
        dbms_output.put_line( dbms_lob.substr( p_clob, 255, l_offset ) );  
        l_offset := l_offset + 255;  
    end loop; 
END;

报错信息

执行时触发如下错误:

ORA-06502: PL/SQL: numeric or value error
ORA-06512: at line 21
ORA-06512: at "SYS.DBMS_SQL", line 1721

问题在于p_parm_value参数接收VARCHAR2类型的表,无法直接传入CLOB;且不愿转成VARCHAR2(存在32KB上限,附件可能达数GB)。求可行解决方法。


解决方案

方法1:使用apex_web_service.make_rest_request_b直接发送BLOB

APEX_WEB_SERVICE提供了专门处理大BLOB的make_rest_request_b过程,需手动构建符合multipart/form-data格式的请求体:

DECLARE
    l_blob BLOB;
    l_boundary VARCHAR2(256) := '----WebKitFormBoundary' || DBMS_RANDOM.string('x', 16);
    l_clob CLOB;
    l_response CLOB;
    v_login VARCHAR2(100) := '***';
    v_password VARCHAR2(100) := '***';
    f_attachment BLOB;
BEGIN
    -- 从表中读取目标BLOB
    SELECT PDF INTO f_attachment FROM VIPUL_TEST WHERE ID=2;
    
    -- 创建临时LOB存储请求体
    DBMS_LOB.CREATETEMPORARY(l_clob, TRUE);
    DBMS_LOB.CREATETEMPORARY(l_blob, TRUE);
    
    -- 构建multipart分隔头信息
    DBMS_LOB.WRITEAPPEND(l_clob, LENGTH('--' || l_boundary || CHR(13) || CHR(10)), '--' || l_boundary || CHR(13) || CHR(10));
    DBMS_LOB.WRITEAPPEND(l_clob, LENGTH('Content-Disposition: form-data; name="filedata"; filename="document.pdf"' || CHR(13) || CHR(10)), 'Content-Disposition: form-data; name="filedata"; filename="document.pdf"' || CHR(13) || CHR(10));
    DBMS_LOB.WRITEAPPEND(l_clob, LENGTH('Content-Type: application/pdf' || CHR(13) || CHR(10) || CHR(13) || CHR(10)), 'Content-Type: application/pdf' || CHR(13) || CHR(10) || CHR(13) || CHR(10));
    
    -- 将文本头转换为BLOB,追加目标文件BLOB
    DBMS_LOB.CONVERTTOBLOB(l_blob, l_clob, DBMS_LOB.LOBMAXSIZE, 1, 1, DBMS_LOB.DEFAULT_CSID);
    DBMS_LOB.APPEND(l_blob, f_attachment);
    
    -- 追加结束分隔符
    DBMS_LOB.WRITEAPPEND(l_clob, LENGTH(CHR(13) || CHR(10) || '--' || l_boundary || '--'), CHR(13) || CHR(10) || '--' || l_boundary || '--');
    DBMS_LOB.CONVERTTOBLOB(l_blob, l_clob, DBMS_LOB.LOBMAXSIZE, DBMS_LOB.GETLENGTH(l_blob)+1, 1, DBMS_LOB.DEFAULT_CSID);
    
    -- 设置请求头
    apex_web_service.g_request_headers.delete;
    apex_web_service.g_request_headers(1).name := 'Content-Type';
    apex_web_service.g_request_headers(1).value := 'multipart/form-data; boundary=' || l_boundary;
    
    -- 发送POST请求
    l_response := apex_web_service.make_rest_request_b(
        p_url => 'https://systest.eisenvault.net/alfresco/api/-default-/public/alfresco/versions/1/nodes/2b9d7fc9-a12e-4e0b-89b2-e556ddfd2778/children',
        p_http_method => 'POST',
        p_username => v_login,
        p_password => v_password,
        p_blob => l_blob
    );
    
    -- 输出响应结果
    DBMS_OUTPUT.PUT_LINE(l_response);
    
    -- 释放临时LOB资源
    DBMS_LOB.FREETEMPORARY(l_clob);
    DBMS_LOB.FREETEMPORARY(l_blob);
END;
/

关键说明

  1. 原代码错误原因:apex_util.string_to_table仅支持VARCHAR2输入,无法处理大CLOB,且make_rest_request的参数模式不适合大文件传输。
  2. 注意事项:
    • 需根据实际文件类型调整Content-Type和文件名
    • 临时LOB使用后必须释放,避免内存泄漏
    • 自动生成随机boundary,避免与文件内容冲突

内容的提问来源于stack exchange,提问作者Vipul Swarup

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 20:55:23