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_code
和l_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 发布