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

使用ORDS REST API从Oracle APEX传输BLOB至远程库时文件损坏

问题:Oracle APEX通过ORDS传输文件后BLOB损坏

在Oracle APEX中通过「文件浏览」项选择图片/文档后,调用ORDS POST API传输至远程数据库,文件存入远程库后BLOB出现损坏。


现有实现细节

1. APEX页面文件项配置

APEX文件项配置

文件上传后会自动存入APEX临时表apex_application_temp_files。

2. 前端上传按钮JS代码

点击「上传」按钮时执行以下JavaScript逻辑:

var fileName = $v('P28_NEW');

var getImageDetails = async function() {
    return apex.server.process(
        "GET_IMAGE_DETAILS", {
            x01: fileName
        }, {
            async: false,
            dataType: "json",
            success: function(pData) {
                console.log('success');
                console.log('requestBody:'+JSON.stringify(pData));
            },
            error: function(request, status, error) {
                alert("Error1:" + error);
            },
        }
    );
};


async function mainFunction() {
    try {
        var callFunction1 = await getImageDetails();

        var apiUrl = '...../ords/..../..../image/api?TITLE=test&FILENAME=test&SUBMITTED_BY=ssss&MIMETYPE=application/pdf';
        var imageContent = callFunction1.image;
        var imageType = callFunction1.mimetype;
       
        fetch(apiUrl, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: imageContent
            })
            .then(function(response) {
                if (response.ok) {
                    console.log('successful');
                } else {
                    console.error('failed');
                }
            })
            .catch(function(error) {
                console.error('Error:', error);
            });

    } catch (e) {
        console.error(e);
    }
}

mainFunction();

3. AJAX调用的PL/SQL过程(GET_IMAGE_DETAILS)

该过程从临时表提取文件内容并返回:

DECLARE
  l_image       CLOB;
  l_mime_type   VARCHAR2 (255);
  l_imag1e varchar2(500):=  APEX_APPLICATION.g_x01;
BEGIN
  SELECT blob_content, mime_type
                  INTO l_image, l_mime_type
                  FROM apex_application_temp_files
                 WHERE name = l_imag1e; 
    
   apex_json.open_object;
   apex_json.write('image', l_image);
   apex_json.write('mimetype', l_mime_type);
   apex_json.close_object; 
EXCEPTION   
   WHEN OTHERS THEN
      apex_json.open_object; 
      apex_json.write('message', sqlerrm);
      apex_json.close_object; 
END;

4. 远程ORDS REST API配置

远程API通过:body参数提取请求内容:
远程ORDS API配置


问题原因及修复方案

核心问题

  1. BLOB直接转CLOB导致数据损坏:PL/SQL中直接将blob_content(二进制类型)赋值给CLOB变量,会因字符编码不匹配破坏二进制结构。
  2. 二进制数据未编码直接JSON传输:JSON无法原生处理二进制内容,直接传输会导致部分字节被错误解析。
  3. 请求Content-Type设置错误:传输二进制文件时使用application/json类型,不符合文件传输的规范。

修复步骤

步骤1:修改PL/SQL过程,将BLOB转为Base64编码字符串

DECLARE
  l_image_base64 VARCHAR2(32767); -- 大文件需改用CLOB配合DBMS_LOB处理
  l_mime_type    VARCHAR2(255);
  l_filename     VARCHAR2(500) := APEX_APPLICATION.g_x01;
  l_blob         BLOB;
BEGIN
  SELECT blob_content, mime_type
    INTO l_blob, l_mime_type
    FROM apex_application_temp_files
   WHERE name = l_filename;

  -- 将BLOB转为Base64编码,避免二进制传输丢失
  l_image_base64 := UTL_ENCODE.base64_encode(l_blob);

  apex_json.open_object;
  apex_json.write('image', l_image_base64);
  apex_json.write('mimetype', l_mime_type);
  apex_json.close_object;
EXCEPTION
  WHEN OTHERS THEN
    apex_json.open_object;
    apex_json.write('message', SQLERRM);
    apex_json.close_object;
END;

步骤2:修改前端JS,正确解码Base64并使用FormData传输

var fileName = $v('P28_NEW');

var getImageDetails = async function() {
    return apex.server.process(
        "GET_IMAGE_DETAILS", {
            x01: fileName
        }, {
            dataType: "json",
            error: function(request, status, error) {
                alert("获取文件详情失败:" + error);
            },
        }
    );
};


async function mainFunction() {
    try {
        var fileData = await getImageDetails();
        if (fileData.message) {
            console.error(fileData.message);
            return;
        }

        // 构造FormData,适配文件传输规范
        var formData = new FormData();
        formData.append('file', atob(fileData.image), fileName);
        formData.append('mimetype', fileData.mimetype);
        formData.append('TITLE', 'test');
        formData.append('SUBMITTED_BY', 'ssss');

        var apiUrl = '...../ords/..../..../image/api';
       
        fetch(apiUrl, {
                method: 'POST',
                body: formData
                // 无需手动设置Content-Type,浏览器会自动添加multipart/form-data及边界
            })
            .then(function(response) {
                if (response.ok) {
                    console.log('文件上传成功');
                } else {
                    console.error('文件上传失败');
                }
            })
            .catch(function(error) {
                console.error('请求错误:', error);
            });

    } catch (e) {
        console.error(e);
    }
}

mainFunction();

步骤3:修改远程ORDS API处理逻辑

如果使用FormData传输,ORDS会自动解析参数,可直接提取BLOB:

DECLARE
  l_blob BLOB;
BEGIN
  -- 从FormData中获取文件BLOB和参数
  l_blob := :file;

  INSERT INTO your_target_table (blob_column, mime_type, filename, title, submitted_by)
  VALUES (l_blob, :mimetype, :filename, :TITLE, :SUBMITTED_BY);
  COMMIT;
END;

如果仍需使用JSON传输,可在远程API中将Base64字符串解码回BLOB:l_blob := UTL_ENCODE.base64_decode(UTL_RAW.cast_to_raw(:body.image));


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 15:45:54