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

Oracle Apex调用REST API返回PDF异常:仅显示填充数据无模板内容

问题概述

我有一个REST API,可接收PDF模板及填充数据,返回已填充数据的PDF文件。该API在Postman中测试正常,但使用Oracle Apex调用时(页面提交时执行如下代码),下载的PDF仅包含填充的数据,模板原有内容丢失。例如模板包含固定文本和表单域,生成的PDF仅显示填充后的表单域,无其他内容。此问题仅在Apex调用时出现。

原代码:

DECLARE
    lc_response     CLOB;
    l_blob          BLOB;
    lm_multipart    apex_web_service.t_multipart_parts;
    lc_json         CLOB := '[{
    "D1": 194645,
    "R1": 1,
    "R2": 9,
    "R3": 4,
    "R4": 6,
    "R5": 4,
    "R6": 5
    }]';
    lv_filename     VARCHAR2(20) := 'my_file.pdf';
    lv_base_url     VARCHAR2(100) := 'http://10.50.200.11:27005/report'; -- webservice base URL; 
    lv_api_key      VARCHAR2(100); -- API KEY 
    lb_blob         BLOB; -- Blob part of the multipart
    l_dest_offset   PLS_INTEGER := 1;
    l_src_offset    PLS_INTEGER := 1;
    l_lang_context  PLS_INTEGER := dbms_lob.default_lang_ctx;
    l_warning       PLS_INTEGER := dbms_lob.warn_inconvertible_char;
    l_file_mimetype apex_application_files.mime_type%TYPE;
BEGIN

    -- Select unfilled PDF template stored as BLOB in database
    SELECT
        input_template
    INTO lb_blob
    FROM
        python_input_template
    WHERE
        sno = 1;

    apex_web_service.set_request_headers(
                                        p_name_01  => 'x-api-key',
                                        p_value_01 => 'qwerty_key',
                                        p_name_02  => 'x-api-user',
                                        p_value_02 => 'APEX'
    );

    /*Supply data to fill the pdf with*/
    apex_web_service.append_to_multipart(
                                        p_multipart    => lm_multipart,
                                        p_name         => 'data_str',
                                        p_content_type => 'application/json',
                                        p_body         => lc_json
    );
    /*Supply the template to be filled*/
    apex_web_service.append_to_multipart(
                                        p_multipart    => lm_multipart,
                                        p_name         => 'template',
                                        p_filename     => lv_filename,
                                        p_content_type => 'application/pdf',
                                        p_body_blob    => lb_blob
    );

    lc_response := apex_web_service.make_rest_request(
                                                     p_url         => lv_base_url,
                                                     p_http_method => 'POST',
                                                     p_body_blob   => apex_web_service.generate_request_body(lm_multipart)
                   ); 

    /*convert CLOB responce to BLOB*/
    dbms_lob.createtemporary(
                            lob_loc => l_blob,
                            cache   => true
    );
    dbms_lob.converttoblob(
                          dest_lob     => l_blob,
                          src_clob     => lc_response,
                          amount       => dbms_lob.lobmaxsize,
                          dest_offset  => l_dest_offset,
                          src_offset   => l_src_offset,
                          blob_csid    => dbms_lob.default_csid,
                          lang_context => l_lang_context,
                          warning      => l_warning
    );

    sys.htp.init;
    owa_util.mime_header(
                        'application/pdf',
                        false,
                        'UTF-8'
    );
    sys.htp.p('Content-Disposition: attachment; filename="'
              || 'l_file_name.pdf'
              || '"');
    sys.htp.p('Content-length: '
              || sys.dbms_lob.getlength(l_blob));

    sys.owa_util.http_header_close;
    wpg_docload.download_file(l_blob);
    apex_application.stop_apex_engine;
END;

可能的原因及解决方法

1. 二进制响应被错误转为CLOB处理

API返回的是二进制PDF文件,原代码先将其作为CLOB接收,再转BLOB的过程中,二进制数据会被当作文本解析,导致PDF结构损坏,仅保留了可识别的文本表单域内容。

  • 解决方法:
    直接使用apex_web_service.make_rest_request_blob接收二进制响应,跳过CLOB转BLOB的步骤,避免数据损坏。

2. 多部分请求的Content-Type头缺失

Postman会自动为多部分请求添加正确的Content-Type头(包含边界标识),但原Apex代码未设置该头,导致API无法正确识别请求中的多部分数据,仅解析了JSON部分。

  • 解决方法:
    显式设置Content-Type为多部分表单格式,结合Apex生成的边界字符串。

3. PDF模板BLOB传递时的潜在损坏

从数据库读取BLOB后,若存在隐式编码转换,可能导致模板内容损坏,API无法正确解析模板的固定文本部分。

  • 解决方法:
    验证数据库中存储的input_template BLOB完整性:将BLOB导出为本地PDF文件,确认模板内容正常;传递时直接使用原始BLOB,不做额外转换。

4. 响应头的UTF-8编码设置错误

PDF是二进制文件,无需设置UTF-8文本编码,原代码的owa_util.mime_header中指定UTF-8可能导致下载的PDF文件异常。

  • 解决方法:
    移除owa_util.mime_header中的UTF-8参数。

修正后的完整代码

DECLARE
    l_blob          BLOB;
    lm_multipart    apex_web_service.t_multipart_parts;
    lc_json         CLOB := '[{
    "D1": 194645,
    "R1": 1,
    "R2": 9,
    "R3": 4,
    "R4": 6,
    "R5": 4,
    "R6": 5
    }]';
    lv_filename     VARCHAR2(20) := 'my_file.pdf';
    lv_base_url     VARCHAR2(100) := 'http://10.50.200.11:27005/report'; -- webservice base URL; 
    lb_blob         BLOB; -- Blob part of the multipart
BEGIN

    -- Select unfilled PDF template stored as BLOB in database
    SELECT
        input_template
    INTO lb_blob
    FROM
        python_input_template
    WHERE
        sno = 1;

    -- 显式设置所有必要请求头,包括多部分Content-Type
    apex_web_service.set_request_headers(
                                        p_name_01  => 'x-api-key',
                                        p_value_01 => 'qwerty_key',
                                        p_name_02  => 'x-api-user',
                                        p_value_02 => 'APEX',
                                        p_name_03  => 'Content-Type',
                                        p_value_03 => 'multipart/form-data; boundary=' || apex_web_service.get_boundary(lm_multipart)
    );

    /*Supply data to fill the pdf with*/
    apex_web_service.append_to_multipart(
                                        p_multipart    => lm_multipart,
                                        p_name         => 'data_str',
                                        p_content_type => 'application/json',
                                        p_body         => lc_json
    );
    /*Supply the template to be filled*/
    apex_web_service.append_to_multipart(
                                        p_multipart    => lm_multipart,
                                        p_name         => 'template',
                                        p_filename     => lv_filename,
                                        p_content_type => 'application/pdf',
                                        p_body_blob    => lb_blob
    );

    -- 直接接收二进制响应,避免CLOB转BLOB的损坏风险
    l_blob := apex_web_service.make_rest_request_blob(
                                                     p_url         => lv_base_url,
                                                     p_http_method => 'POST',
                                                     p_body_blob   => apex_web_service.generate_request_body(lm_multipart)
                   ); 

    sys.htp.init;
    -- PDF是二进制文件,无需指定UTF-8编码
    owa_util.mime_header(
                        'application/pdf',
                        false
    );
    sys.htp.p('Content-Disposition: attachment; filename="'
              || 'filled_template.pdf'
              || '"');
    sys.htp.p('Content-length: '
              || sys.dbms_lob.getlength(l_blob));

    sys.owa_util.http_header_close;
    wpg_docload.download_file(l_blob);
    apex_application.stop_apex_engine;
END;

内容的提问来源于stack exchange,提问作者Arif Sher Khan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 20:55:58