PL/SQL UTL_HTTP 发送多个原始数据

Posted

技术标签:

【中文标题】PL/SQL UTL_HTTP 发送多个原始数据【英文标题】:PL/SQL UTL_HTTP send multiple raws 【发布时间】:2020-05-29 08:54:33 【问题描述】:

我正在尝试使用 webservice POST 方法向另一方发送数十条记录,但问题是另一方仅获得一个原始数据。 我把光标放在开始部分打开光标并循环。 我认为问题出在 UTL_HTTP.read_raw 的某个地方。我必须添加一些额外的东西或修改功能。 问题在哪里,我错在哪里?

创建或替换 FUNCTION "TST" 返回 clob 是

l_http_request   UTL_HTTP.req;
l_http_response  UTL_HTTP.resp;
l_buffer_size    NUMBER(10) := 20000;
l_line_size      NUMBER(10) := 50;
l_lines_count    NUMBER(10) := 20;
l_string_request VARCHAR2(32767);
l_line           VARCHAR2(128);
l_substring_msg  VARCHAR2(20000);
l_raw_data       RAW(20000);
l_clob_response  CLOB ;
v_clob clob;
url varchar2(200) := 'http://tst';

cursor c_get_prihod is 
select     IDORIG   ,    IDSUSTAVA  ,    DATUM  ,    SIFAGENCIJE    ,    SIFDRZAVE  ,
SIFOSUSL    ,    IZNOSNETO  ,    IZNOSBRUTO ,    IZNOSPOREZA    ,    SIFHOTELA
from HRS_LASERLINE_PRIHOD
where datum = pms_p.business_date
and sifhotela = pms_p.resort
;

begin

for a in c_get_prihod loop

l_string_request:= 
'
IdOrig:"'||a.IDORIG||'",
IdSustava:"'||a.IDSUSTAVA||'",
Datum:"'||a.DATUM||'",
SifAgencije:"'||a.SIFAGENCIJE||'",
SifDrzave:"'||a.SIFDRZAVE||'",
SifOsUsl:"'||a.SIFOSUSL||'",
IznosNeto:"'||a.IZNOSNETO||'",
IznosBruto:"'||a.IZNOSBRUTO||'",
IznosPoreza:"'||a.IZNOSPOREZA||'",
SifHotela:"'||a.SIFHOTELA||'",
'
;

end loop;

l_http_request := UTL_HTTP.begin_request(url , method => 'POST', http_version => 'HTTP/1.1');
utl_http.set_header(l_http_request, 'user-agent', 'mozilla/4.0'); 
utl_http.set_header(l_http_request, 'content-type', 'application/json'); 
utl_http.set_header(l_http_request, 'Content-Length', length(l_string_request));

BEGIN

<<request_loop>>

FOR i IN 0..CEIL(LENGTH(l_string_request) / l_buffer_size) - 1 LOOP
    l_substring_msg := SUBSTR(l_string_request, i * l_buffer_size + 1, l_buffer_size);

BEGIN
    l_raw_data := utl_raw.cast_to_raw(l_substring_msg);
    UTL_HTTP.write_raw(r => l_http_request, data => l_raw_data);

EXCEPTION

WHEN NO_DATA_FOUND THEN
EXIT request_loop;

END;
END LOOP request_loop;

l_http_response := UTL_HTTP.get_response(l_http_request);

BEGIN

LOOP
    UTL_HTTP.read_raw(l_http_response, l_raw_data, l_buffer_size);
    l_clob_response := l_clob_response || UTL_RAW.cast_to_varchar2(l_raw_data);
END LOOP response_loop; 

EXCEPTION

WHEN UTL_HTTP.end_of_body THEN
    UTL_HTTP.end_response(l_http_response);
END; 

<<print_response>>

FOR i IN 0..CEIL(LENGTH(l_clob_response) / l_line_size) - 1 
LOOP
    l_line := SUBSTR(l_clob_response, i * l_line_size + 1, l_line_size);
EXIT WHEN i > l_lines_count - 1;
END LOOP print_response;

v_clob:= l_clob_response;        

return v_clob ;

exception
  when utl_http.end_of_body then
  utl_http.end_response(l_http_response);
end;
end TST;

【问题讨论】:

您是否希望c_get_prihod 返回数十行?你做了哪些调试来检查正在生产、发送和接收的内容?此外 - 您使用的是哪个版本的 Oracle - 从 12cR1 添加了内置 JSON 功能;最初非常基本,但此后一直在扩展。 是的,c_get_prihod 返回了几十个应该通过 web 服务传输的原始数据。他们只收到了一张唱片。 Oracle 版本为 11.2.0.4.20 【参考方案1】:

您的游标查询可能会找到几十行,但您正在这样做:

for a in c_get_prihod loop

l_string_request:= ... ;

end loop;

每次在循环中替换l_string_request 的全部内容,所以无论你得到多少行以及循环多少次,你总是会得到包含该查询返回的最后一行。因此,您只需将单个最终记录发送到 Web 服务。

假设接收服务需要一个记录数组,您可能需要类似:

begin

  l_string_request := '[ ';

  for a in c_get_prihod loop
    if a.FLAG > 1 then
      l_string_request := l_string_request || ', ';
    end if;
    l_string_request := l_string_request || ' ';
    l_string_request := l_string_request || '"IdOrig": "' || a.IDORIG || '", ';
    l_string_request := l_string_request || '"IdSustava": "' || a.IDSUSTAVA ||' ", ';
    l_string_request := l_string_request || '"Datum": "' || a.DATUM || '", ';
    l_string_request := l_string_request || '"SifAgencije": "' || a.SIFAGENCIJE || '", ';
    l_string_request := l_string_request || '"SifDrzave": "' || a.SIFDRZAVE || '", ';
    l_string_request := l_string_request || '"SifOsUsl": "' || a.SIFOSUSL || '", ';
    l_string_request := l_string_request || '"IznosNeto": "' || a.IZNOSNETO || '", ';
    l_string_request := l_string_request || '"IznosBruto": "' || a.IZNOSBRUTO || '", ';
    l_string_request := l_string_request || '"IznosPoreza": "' || a.IZNOSPOREZA || '", ';
    l_string_request := l_string_request || '"SifHotela": "' || a.SIFHOTELA || '"';
    l_string_request := l_string_request || ' ';
  end loop;
  
  l_string_request := l_string_request || ' ]';

  dbms_output.put_line(l_string_request);

  ...

其中flag 是添加到游标结果的额外列,例如, ROWNUM AS FLAG - 作为一种机制来了解您是在第一行还是在后续行(因此需要在数组元素之间使用逗号)。

dbms_output 让您可以看到整个生成的值,您可以手动检查和/或通过 JSON 验证器来检查它是否是您(更重要的是接收服务)期望看到的。您仍然可以在 JSON 构造期间添加换行符以提高可读性,尽管服务不会关心这些。

根据您可以拥有的行数,您可能需要 l_string_request 成为 CLOB 而不是 varchar2。我还建议您明确格式化日期/时间戳值,并正确处理数字(如果有)。


根据您的建议修改后,我收到此错误:

ORA-06502:PL/SQL:数字或值错误 ORA-06512:在“OPERA_MARRIOTT.HRS_LASERLINE_BI_PRIHOD”,第 87 行

如果l_clob_response 是空的,你会得到这个,所以你的读取循环可能没有得到你现在所期望的。 (这很可能是因为请求现在是无效的 JSON,或者与服务所期望的不匹配)。在UTL_HTTP.get_response() 调用之后,查看l_http_response.status_codel_http_response.reason_phrase 显示的内容。状态码are in the documentation。

【讨论】:

以上是关于PL/SQL UTL_HTTP 发送多个原始数据的主要内容,如果未能解决你的问题,请参考以下文章

ORA-29259 输入结束调用 utl_http.get_response PL/SQL

如何通过PL / SQL utl_http.html_pieces确定一个部分

对于使用 Oracle pl sql 的 http 请求,是不是有替代 utl_http 包的方法?

确定需要哪个证书才能使用 Oracle utl_http 执行 https 发布

ORA-29270:从pl / sql过程调用webservice时,有太多打开的HTTP请求

Oracle PL/SQL 实现发送电子邮件功能(UTL_MAIL)